Auto merge of #5141 - xiongmao86:issue5095, r=flip1995
Fixes issue 5095 fixes #5095. - [x] Followed [lint naming conventions][lint_naming] - [x] Added passing UI tests (including committed `.stderr` file) - [x] `cargo test` passes locally - [x] Executed `cargo dev update_lints` - [x] Added lint documentation - [x] Run `cargo dev fmt` [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints changelog: (internal) warn about collapsible `span_lint_and_then` calls.
This commit is contained in:
commit
6dcc8d5038
|
@ -50,6 +50,7 @@ impl EarlyLintPass for AsConversions {
|
|||
AS_CONVERSIONS,
|
||||
expr.span,
|
||||
"using a potentially dangerous silent `as` conversion",
|
||||
None,
|
||||
"consider using a safe wrapper for this conversion",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssertionsOnConstants {
|
|||
} else {
|
||||
"`assert!(true)` will be optimized out by the compiler"
|
||||
},
|
||||
None,
|
||||
"remove it",
|
||||
);
|
||||
};
|
||||
|
@ -50,6 +51,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssertionsOnConstants {
|
|||
ASSERTIONS_ON_CONSTANTS,
|
||||
e.span,
|
||||
"`assert!(false)` should probably be replaced",
|
||||
None,
|
||||
"use `panic!()` or `unreachable!()`",
|
||||
);
|
||||
};
|
||||
|
@ -59,6 +61,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssertionsOnConstants {
|
|||
ASSERTIONS_ON_CONSTANTS,
|
||||
e.span,
|
||||
&format!("`assert!(false, {})` should probably be replaced", panic_message),
|
||||
None,
|
||||
&format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message),
|
||||
)
|
||||
};
|
||||
|
|
|
@ -85,6 +85,7 @@ fn check_atomic_load_store(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
|
|||
INVALID_ATOMIC_ORDERING,
|
||||
ordering_arg.span,
|
||||
"atomic loads cannot have `Release` and `AcqRel` ordering",
|
||||
None,
|
||||
"consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`"
|
||||
);
|
||||
} else if method == "store" &&
|
||||
|
@ -94,6 +95,7 @@ fn check_atomic_load_store(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
|
|||
INVALID_ATOMIC_ORDERING,
|
||||
ordering_arg.span,
|
||||
"atomic stores cannot have `Acquire` and `AcqRel` ordering",
|
||||
None,
|
||||
"consider using ordering modes `Release`, `SeqCst` or `Relaxed`"
|
||||
);
|
||||
}
|
||||
|
@ -118,6 +120,7 @@ fn check_memory_fence(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
|
|||
INVALID_ATOMIC_ORDERING,
|
||||
args[0].span,
|
||||
"memory fences cannot have `Relaxed` ordering",
|
||||
None,
|
||||
"consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -105,6 +105,7 @@ impl CognitiveComplexity {
|
|||
rust_cc,
|
||||
self.limit.limit()
|
||||
),
|
||||
None,
|
||||
"you could split it up into multiple smaller functions",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ComparisonChain {
|
|||
COMPARISON_CHAIN,
|
||||
expr.span,
|
||||
"`if` chain can be rewritten with `match`",
|
||||
None,
|
||||
"Consider rewriting the `if` chain to use `cmp` and `match`.",
|
||||
)
|
||||
}
|
||||
|
|
|
@ -183,7 +183,7 @@ fn lint_same_then_else(cx: &LateContext<'_, '_>, blocks: &[&Block<'_>]) {
|
|||
IF_SAME_THEN_ELSE,
|
||||
j.span,
|
||||
"this `if` has identical blocks",
|
||||
i.span,
|
||||
Some(i.span),
|
||||
"same as this",
|
||||
);
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr<'_>]) {
|
|||
IFS_SAME_COND,
|
||||
j.span,
|
||||
"this `if` has the same condition as a previous `if`",
|
||||
i.span,
|
||||
Some(i.span),
|
||||
"same as this",
|
||||
);
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_, '_>, conds: &[&Expr<'_>]) {
|
|||
SAME_FUNCTIONS_IN_IF_CONDITION,
|
||||
j.span,
|
||||
"this `if` has the same function call as a previous `if`",
|
||||
i.span,
|
||||
Some(i.span),
|
||||
"same as this",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyIterator {
|
|||
COPY_ITERATOR,
|
||||
item.span,
|
||||
"you are implementing `Iterator` on a `Copy` type",
|
||||
item.span,
|
||||
None,
|
||||
"consider implementing `IntoIterator` instead",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ impl EarlyLintPass for DbgMacro {
|
|||
DBG_MACRO,
|
||||
mac.span(),
|
||||
"`dbg!` macro is intended as a debugging tool",
|
||||
None,
|
||||
"ensure to avoid having uses of it in version control",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::utils::paths;
|
||||
use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_then};
|
||||
use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_note, span_lint_and_then};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{Item, ItemKind, TraitRef};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -163,14 +163,13 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item<'_>, trait
|
|||
_ => (),
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
EXPL_IMPL_CLONE_ON_COPY,
|
||||
item.span,
|
||||
"you are implementing `Clone` explicitly on a `Copy` type",
|
||||
|diag| {
|
||||
diag.span_note(item.span, "consider deriving `Clone` or removing `Copy`");
|
||||
},
|
||||
Some(item.span),
|
||||
"consider deriving `Clone` or removing `Copy`",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DropForgetRef {
|
|||
lint,
|
||||
expr.span,
|
||||
&msg,
|
||||
arg.span,
|
||||
Some(arg.span),
|
||||
&format!("argument has type `{}`", arg_ty));
|
||||
} else if is_copy(cx, arg_ty) {
|
||||
if match_def_path(cx, def_id, &paths::DROP) {
|
||||
|
@ -151,7 +151,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DropForgetRef {
|
|||
lint,
|
||||
expr.span,
|
||||
&msg,
|
||||
arg.span,
|
||||
Some(arg.span),
|
||||
&format!("argument has type {}", arg_ty));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ impl EarlyLintPass for ElseIfWithoutElse {
|
|||
ELSE_IF_WITHOUT_ELSE,
|
||||
els.span,
|
||||
"`if` expression with an `else if`, but without a final `else`",
|
||||
None,
|
||||
"add an `else` block here",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! lint when there is an enum with no variants
|
||||
|
||||
use crate::utils::span_lint_and_then;
|
||||
use crate::utils::span_lint_and_help;
|
||||
use rustc_hir::{Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
@ -45,13 +45,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EmptyEnum {
|
|||
let ty = cx.tcx.type_of(did);
|
||||
let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
|
||||
if adt.variants.is_empty() {
|
||||
span_lint_and_then(cx, EMPTY_ENUM, item.span, "enum with no variants", |diag| {
|
||||
diag.span_help(
|
||||
item.span,
|
||||
"consider using the uninhabited type `!` (never type) or a wrapper \
|
||||
around it to introduce a type which can't be instantiated",
|
||||
);
|
||||
});
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
EMPTY_ENUM,
|
||||
item.span,
|
||||
"enum with no variants",
|
||||
None,
|
||||
"consider using the uninhabited type `!` (never type) or a wrapper \
|
||||
around it to introduce a type which can't be instantiated",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -206,6 +206,7 @@ fn check_variant(
|
|||
lint,
|
||||
span,
|
||||
&format!("All variants have the same {}fix: `{}`", what, value),
|
||||
None,
|
||||
&format!(
|
||||
"remove the {}fixes and use full paths to \
|
||||
the variants instead of glob imports",
|
||||
|
|
|
@ -7,7 +7,8 @@ use rustc_middle::ty::{self, Ty};
|
|||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
use crate::utils::{
|
||||
implements_trait, is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then, type_is_unsafe_function,
|
||||
implements_trait, is_adjusted, iter_input_pats, snippet_opt, span_lint_and_sugg, span_lint_and_then,
|
||||
type_is_unsafe_function,
|
||||
};
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
@ -131,14 +132,15 @@ fn check_closure(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
|
|||
if let Some(name) = get_ufcs_type_name(cx, method_def_id, &args[0]);
|
||||
|
||||
then {
|
||||
span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure found", |diag| {
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"remove closure as shown",
|
||||
format!("{}::{}", name, path.ident.name),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
});
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
|
||||
expr.span,
|
||||
"redundant closure found",
|
||||
"remove closure as shown",
|
||||
format!("{}::{}", name, path.ident.name),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -310,7 +310,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
|
|||
EVAL_ORDER_DEPENDENCE,
|
||||
expr.span,
|
||||
"unsequenced read of a variable",
|
||||
self.write_expr.span,
|
||||
Some(self.write_expr.span),
|
||||
"whether read occurs before this write depends on evaluation order"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -114,6 +114,7 @@ impl ExcessiveBools {
|
|||
FN_PARAMS_EXCESSIVE_BOOLS,
|
||||
span,
|
||||
&format!("more than {} bools in function parameters", self.max_fn_params_bools),
|
||||
None,
|
||||
"consider refactoring bools into two-variant enums",
|
||||
);
|
||||
}
|
||||
|
@ -153,6 +154,7 @@ impl EarlyLintPass for ExcessiveBools {
|
|||
STRUCT_EXCESSIVE_BOOLS,
|
||||
item.span,
|
||||
&format!("more than {} bools in a struct", self.max_struct_bools),
|
||||
None,
|
||||
"consider using a state machine or refactoring bools into two-variant enums",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
|
|||
really are doing `.. = ({op} ..)`",
|
||||
op = op
|
||||
),
|
||||
eqop_span,
|
||||
None,
|
||||
&format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
|
||||
);
|
||||
}
|
||||
|
@ -188,6 +188,7 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) {
|
|||
binop = binop_str,
|
||||
unop = unop_str
|
||||
),
|
||||
None,
|
||||
&format!(
|
||||
"put a space between `{binop}` and `{unop}` and remove the space after `{unop}`",
|
||||
binop = binop_str,
|
||||
|
@ -226,7 +227,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
|
|||
SUSPICIOUS_ELSE_FORMATTING,
|
||||
else_span,
|
||||
&format!("this is an `else {}` but the formatting might hide it", else_desc),
|
||||
else_span,
|
||||
None,
|
||||
&format!(
|
||||
"to remove this lint, remove the `else` or remove the new line between \
|
||||
`else` and `{}`",
|
||||
|
@ -265,7 +266,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
|
|||
POSSIBLE_MISSING_COMMA,
|
||||
lint_span,
|
||||
"possibly missing a comma here",
|
||||
lint_span,
|
||||
None,
|
||||
"to remove this lint, add a comma or write the expr in a single line",
|
||||
);
|
||||
}
|
||||
|
@ -296,7 +297,7 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
|
|||
SUSPICIOUS_ELSE_FORMATTING,
|
||||
else_span,
|
||||
&format!("this looks like {} but the `else` is missing", looks_like),
|
||||
else_span,
|
||||
None,
|
||||
&format!(
|
||||
"to remove this lint, add the missing `else` or add a new line before {}",
|
||||
next_thing,
|
||||
|
|
|
@ -431,6 +431,7 @@ fn check_needless_must_use(
|
|||
DOUBLE_MUST_USE,
|
||||
fn_header_span,
|
||||
"this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`",
|
||||
None,
|
||||
"either add some descriptive text or remove the attribute",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::utils::{
|
||||
match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_then,
|
||||
match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_sugg,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
|
||||
|
@ -58,14 +58,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion {
|
|||
if same_tys(cx, a, b) {
|
||||
let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
|
||||
|
||||
span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |diag| {
|
||||
diag.span_suggestion(
|
||||
e.span,
|
||||
"consider removing `.into()`",
|
||||
sugg,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
});
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
IDENTITY_CONVERSION,
|
||||
e.span,
|
||||
"identical conversion",
|
||||
"consider removing `.into()`",
|
||||
sugg,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
}
|
||||
}
|
||||
if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" {
|
||||
|
@ -73,14 +74,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion {
|
|||
let b = cx.tables.expr_ty(&args[0]);
|
||||
if same_tys(cx, a, b) {
|
||||
let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
|
||||
span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |diag| {
|
||||
diag.span_suggestion(
|
||||
e.span,
|
||||
"consider removing `.into_iter()`",
|
||||
sugg,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
});
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
IDENTITY_CONVERSION,
|
||||
e.span,
|
||||
"identical conversion",
|
||||
"consider removing `.into_iter()`",
|
||||
sugg,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -95,14 +97,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion {
|
|||
let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned();
|
||||
let sugg_msg =
|
||||
format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
|
||||
span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |diag| {
|
||||
diag.span_suggestion(
|
||||
e.span,
|
||||
&sugg_msg,
|
||||
sugg,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
});
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
IDENTITY_CONVERSION,
|
||||
e.span,
|
||||
"identical conversion",
|
||||
&sugg_msg,
|
||||
sugg,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ impl EarlyLintPass for IfNotElse {
|
|||
IF_NOT_ELSE,
|
||||
item.span,
|
||||
"Unnecessary boolean `not` operation",
|
||||
None,
|
||||
"remove the `!` and swap the blocks of the `if`/`else`",
|
||||
);
|
||||
},
|
||||
|
@ -70,6 +71,7 @@ impl EarlyLintPass for IfNotElse {
|
|||
IF_NOT_ELSE,
|
||||
item.span,
|
||||
"Unnecessary `!=` operation",
|
||||
None,
|
||||
"change to `==` and swap the blocks of the `if`/`else`",
|
||||
);
|
||||
},
|
||||
|
|
|
@ -138,7 +138,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
|
|||
(None, None) => return, // [..] is ok.
|
||||
};
|
||||
|
||||
span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic.", help_msg);
|
||||
span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic.", None, help_msg);
|
||||
} else {
|
||||
// Catchall non-range index, i.e., [n] or [n << m]
|
||||
if let ty::Array(..) = ty.kind {
|
||||
|
@ -154,6 +154,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
|
|||
INDEXING_SLICING,
|
||||
expr.span,
|
||||
"indexing may panic.",
|
||||
None,
|
||||
"Consider using `.get(n)` or `.get_mut(n)` instead",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -137,6 +137,7 @@ fn show_lint(cx: &LateContext<'_, '_>, item: &ImplItem<'_>) {
|
|||
"type `{}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`",
|
||||
self_type.to_string()
|
||||
),
|
||||
None,
|
||||
&format!("remove the inherent method from type `{}`", self_type.to_string())
|
||||
);
|
||||
} else {
|
||||
|
@ -148,6 +149,7 @@ fn show_lint(cx: &LateContext<'_, '_>, item: &ImplItem<'_>) {
|
|||
"implementation of inherent method `to_string(&self) -> String` for type `{}`",
|
||||
self_type.to_string()
|
||||
),
|
||||
None,
|
||||
&format!("implement trait `Display` for type `{}` instead", self_type.to_string()),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use rustc_errors::Applicability;
|
|||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
use crate::utils::{snippet_opt, span_lint_and_then};
|
||||
use crate::utils::{snippet_opt, span_lint_and_sugg};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
|
||||
|
@ -149,19 +149,14 @@ impl IntPlusOne {
|
|||
}
|
||||
|
||||
fn emit_warning(cx: &EarlyContext<'_>, block: &Expr, recommendation: String) {
|
||||
span_lint_and_then(
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
INT_PLUS_ONE,
|
||||
block.span,
|
||||
"Unnecessary `>= y + 1` or `x - 1 >=`",
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
block.span,
|
||||
"change it to",
|
||||
recommendation,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
},
|
||||
"change it to",
|
||||
recommendation,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IntegerDivision {
|
|||
INTEGER_DIVISION,
|
||||
expr.span,
|
||||
"integer division",
|
||||
None,
|
||||
"division of integers may cause loss of precision. consider using floats.",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeStackArrays {
|
|||
"allocating a local array larger than {} bytes",
|
||||
self.maximum_allowed_size
|
||||
),
|
||||
None,
|
||||
&format!(
|
||||
"consider allocating on the heap with `vec!{}.into_boxed_slice()`",
|
||||
snippet(cx, expr.span, "[...]")
|
||||
|
|
|
@ -90,6 +90,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore {
|
|||
LET_UNDERSCORE_LOCK,
|
||||
local.span,
|
||||
"non-binding let on a synchronization lock",
|
||||
None,
|
||||
"consider using an underscore-prefixed named \
|
||||
binding or dropping explicitly with `std::mem::drop`"
|
||||
)
|
||||
|
@ -99,6 +100,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore {
|
|||
LET_UNDERSCORE_MUST_USE,
|
||||
local.span,
|
||||
"non-binding let on an expression with `#[must_use]` type",
|
||||
None,
|
||||
"consider explicitly using expression value"
|
||||
)
|
||||
} else if is_must_use_func_call(cx, init) {
|
||||
|
@ -107,6 +109,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore {
|
|||
LET_UNDERSCORE_MUST_USE,
|
||||
local.span,
|
||||
"non-binding let on a result of a `#[must_use]` function",
|
||||
None,
|
||||
"consider explicitly using function result"
|
||||
)
|
||||
}
|
||||
|
|
|
@ -838,6 +838,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
&unwrap::UNNECESSARY_UNWRAP,
|
||||
&use_self::USE_SELF,
|
||||
&utils::internal_lints::CLIPPY_LINTS_INTERNAL,
|
||||
&utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
|
||||
&utils::internal_lints::COMPILER_LINT_FUNCTIONS,
|
||||
&utils::internal_lints::DEFAULT_LINT,
|
||||
&utils::internal_lints::LINT_WITHOUT_LINT_PASS,
|
||||
|
@ -1051,6 +1052,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|| box unnamed_address::UnnamedAddress);
|
||||
store.register_late_pass(|| box dereference::Dereferencing);
|
||||
store.register_late_pass(|| box future_not_send::FutureNotSend);
|
||||
store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
|
||||
|
||||
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
|
||||
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
|
||||
|
@ -1162,6 +1164,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
|
||||
store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
|
||||
LintId::of(&utils::internal_lints::CLIPPY_LINTS_INTERNAL),
|
||||
LintId::of(&utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
|
||||
LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS),
|
||||
LintId::of(&utils::internal_lints::DEFAULT_LINT),
|
||||
LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS),
|
||||
|
|
|
@ -1402,6 +1402,7 @@ fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>) {
|
|||
`if let` statement.",
|
||||
snippet(cx, arg.span, "_")
|
||||
),
|
||||
None,
|
||||
&format!(
|
||||
"consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`",
|
||||
snippet(cx, pat.span, "_"),
|
||||
|
@ -1418,6 +1419,7 @@ fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>) {
|
|||
`if let` statement.",
|
||||
snippet(cx, arg.span, "_")
|
||||
),
|
||||
None,
|
||||
&format!(
|
||||
"consider replacing `for {0} in {1}` with `if let Ok({0}) = {1}`",
|
||||
snippet(cx, pat.span, "_"),
|
||||
|
@ -2471,45 +2473,53 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, '
|
|||
match_type(cx, ty, &paths::HASHMAP) {
|
||||
if method.ident.name == sym!(len) {
|
||||
let span = shorten_needless_collect_span(expr);
|
||||
span_lint_and_then(cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, |diag| {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"replace with",
|
||||
".count()".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
});
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
NEEDLESS_COLLECT,
|
||||
span,
|
||||
NEEDLESS_COLLECT_MSG,
|
||||
"replace with",
|
||||
".count()".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
if method.ident.name == sym!(is_empty) {
|
||||
let span = shorten_needless_collect_span(expr);
|
||||
span_lint_and_then(cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, |diag| {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"replace with",
|
||||
".next().is_none()".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
});
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
NEEDLESS_COLLECT,
|
||||
span,
|
||||
NEEDLESS_COLLECT_MSG,
|
||||
"replace with",
|
||||
".next().is_none()".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
if method.ident.name == sym!(contains) {
|
||||
let contains_arg = snippet(cx, args[1].span, "??");
|
||||
let span = shorten_needless_collect_span(expr);
|
||||
span_lint_and_then(cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, |diag| {
|
||||
let (arg, pred) = if contains_arg.starts_with('&') {
|
||||
("x", &contains_arg[1..])
|
||||
} else {
|
||||
("&x", &*contains_arg)
|
||||
};
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"replace with",
|
||||
format!(
|
||||
".any(|{}| x == {})",
|
||||
arg, pred
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
});
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_COLLECT,
|
||||
span,
|
||||
NEEDLESS_COLLECT_MSG,
|
||||
|diag| {
|
||||
let (arg, pred) = if contains_arg.starts_with('&') {
|
||||
("x", &contains_arg[1..])
|
||||
} else {
|
||||
("&x", &*contains_arg)
|
||||
};
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"replace with",
|
||||
format!(
|
||||
".any(|{}| x == {})",
|
||||
arg, pred
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ impl LateLintPass<'_, '_> for MainRecursion {
|
|||
MAIN_RECURSION,
|
||||
func.span,
|
||||
&format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")),
|
||||
None,
|
||||
"consider using another function for this recursion"
|
||||
)
|
||||
}
|
||||
|
|
|
@ -441,6 +441,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
|
|||
REST_PAT_IN_FULLY_BOUND_STRUCTS,
|
||||
pat.span,
|
||||
"unnecessary use of `..` pattern in struct binding. All fields were already bound",
|
||||
None,
|
||||
"consider removing `..` from this binding",
|
||||
);
|
||||
}
|
||||
|
@ -636,7 +637,7 @@ fn check_overlapping_arms<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ex: &'tcx Expr<'
|
|||
MATCH_OVERLAPPING_ARM,
|
||||
start.span,
|
||||
"some ranges overlap",
|
||||
end.span,
|
||||
Some(end.span),
|
||||
"overlaps with this",
|
||||
);
|
||||
}
|
||||
|
@ -674,7 +675,7 @@ fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>])
|
|||
MATCH_WILD_ERR_ARM,
|
||||
arm.pat.span,
|
||||
&format!("`Err({})` matches all errors", &ident_bind_name),
|
||||
arm.pat.span,
|
||||
None,
|
||||
"match each error separately or use the error output",
|
||||
);
|
||||
}
|
||||
|
@ -887,6 +888,7 @@ fn check_wild_in_or_pats(cx: &LateContext<'_, '_>, arms: &[Arm<'_>]) {
|
|||
WILDCARD_IN_OR_PATTERNS,
|
||||
arm.pat.span,
|
||||
"wildcard pattern covers any other pattern as it will match anyway.",
|
||||
None,
|
||||
"Consider handling `_` separately.",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -148,6 +148,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr<'_>, expr_span
|
|||
MEM_REPLACE_WITH_UNINIT,
|
||||
expr_span,
|
||||
"replacing with `mem::uninitialized()`",
|
||||
None,
|
||||
"consider using the `take_mut` crate instead",
|
||||
);
|
||||
} else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) &&
|
||||
|
@ -157,6 +158,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr<'_>, expr_span
|
|||
MEM_REPLACE_WITH_UNINIT,
|
||||
expr_span,
|
||||
"replacing with `mem::zeroed()`",
|
||||
None,
|
||||
"consider using a default value or the `take_mut` crate instead",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2255,6 +2255,7 @@ fn lint_iter_nth<'a, 'tcx>(
|
|||
ITER_NTH,
|
||||
expr.span,
|
||||
&format!("called `.iter{0}().nth()` on a {1}", mut_str, caller_type),
|
||||
None,
|
||||
&format!("calling `.get{}()` is both faster and more readable", mut_str),
|
||||
);
|
||||
}
|
||||
|
@ -2364,6 +2365,7 @@ fn lint_iter_skip_next(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) {
|
|||
ITER_SKIP_NEXT,
|
||||
expr.span,
|
||||
"called `skip(x).next()` on an iterator",
|
||||
None,
|
||||
"this is more succinctly expressed by calling `nth(x)`",
|
||||
);
|
||||
}
|
||||
|
@ -2431,6 +2433,7 @@ fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, unwrap_args: &[hi
|
|||
lint,
|
||||
expr.span,
|
||||
&format!("used `unwrap()` on `{}` value", kind,),
|
||||
None,
|
||||
&format!(
|
||||
"if you don't want to handle the `{}` case gracefully, consider \
|
||||
using `expect()` to provide a better panic message",
|
||||
|
@ -2458,6 +2461,7 @@ fn lint_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, expect_args: &[hi
|
|||
lint,
|
||||
expr.span,
|
||||
&format!("used `expect()` on `{}` value", kind,),
|
||||
None,
|
||||
&format!("if this value is an `{}`, it will panic", none_value,),
|
||||
);
|
||||
}
|
||||
|
@ -2478,6 +2482,7 @@ fn lint_ok_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, ok_args: &[hir
|
|||
OK_EXPECT,
|
||||
expr.span,
|
||||
"called `ok().expect()` on a `Result` value",
|
||||
None,
|
||||
"you can call `expect()` directly on the `Result`",
|
||||
);
|
||||
}
|
||||
|
@ -2572,7 +2577,7 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
|
|||
},
|
||||
expr.span,
|
||||
msg,
|
||||
expr.span,
|
||||
None,
|
||||
&format!(
|
||||
"replace `map({0}).unwrap_or_else({1})` with `map_or_else({1}, {0})`",
|
||||
map_snippet, unwrap_snippet,
|
||||
|
@ -2752,7 +2757,7 @@ fn lint_filter_next<'a, 'tcx>(
|
|||
FILTER_NEXT,
|
||||
expr.span,
|
||||
msg,
|
||||
expr.span,
|
||||
None,
|
||||
&format!("replace `filter({0}).next()` with `find({0})`", filter_snippet),
|
||||
);
|
||||
} else {
|
||||
|
@ -2774,6 +2779,7 @@ fn lint_skip_while_next<'a, 'tcx>(
|
|||
SKIP_WHILE_NEXT,
|
||||
expr.span,
|
||||
"called `skip_while(p).next()` on an `Iterator`",
|
||||
None,
|
||||
"this is more succinctly expressed by calling `.find(!p)` instead",
|
||||
);
|
||||
}
|
||||
|
@ -2790,7 +2796,7 @@ fn lint_filter_map<'a, 'tcx>(
|
|||
if match_trait_method(cx, expr, &paths::ITERATOR) {
|
||||
let msg = "called `filter(p).map(q)` on an `Iterator`";
|
||||
let hint = "this is more succinctly expressed by calling `.filter_map(..)` instead";
|
||||
span_lint_and_help(cx, FILTER_MAP, expr.span, msg, hint);
|
||||
span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2810,7 +2816,7 @@ fn lint_filter_map_next<'a, 'tcx>(
|
|||
FILTER_MAP_NEXT,
|
||||
expr.span,
|
||||
msg,
|
||||
expr.span,
|
||||
None,
|
||||
&format!("replace `filter_map({0}).next()` with `find_map({0})`", filter_snippet),
|
||||
);
|
||||
} else {
|
||||
|
@ -2830,7 +2836,7 @@ fn lint_find_map<'a, 'tcx>(
|
|||
if match_trait_method(cx, &map_args[0], &paths::ITERATOR) {
|
||||
let msg = "called `find(p).map(q)` on an `Iterator`";
|
||||
let hint = "this is more succinctly expressed by calling `.find_map(..)` instead";
|
||||
span_lint_and_help(cx, FIND_MAP, expr.span, msg, hint);
|
||||
span_lint_and_help(cx, FIND_MAP, expr.span, msg, None, hint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2845,7 +2851,7 @@ fn lint_filter_map_map<'a, 'tcx>(
|
|||
if match_trait_method(cx, expr, &paths::ITERATOR) {
|
||||
let msg = "called `filter_map(p).map(q)` on an `Iterator`";
|
||||
let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead";
|
||||
span_lint_and_help(cx, FILTER_MAP, expr.span, msg, hint);
|
||||
span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2861,7 +2867,7 @@ fn lint_filter_flat_map<'a, 'tcx>(
|
|||
let msg = "called `filter(p).flat_map(q)` on an `Iterator`";
|
||||
let hint = "this is more succinctly expressed by calling `.flat_map(..)` \
|
||||
and filtering by returning `iter::empty()`";
|
||||
span_lint_and_help(cx, FILTER_MAP, expr.span, msg, hint);
|
||||
span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2877,7 +2883,7 @@ fn lint_filter_map_flat_map<'a, 'tcx>(
|
|||
let msg = "called `filter_map(p).flat_map(q)` on an `Iterator`";
|
||||
let hint = "this is more succinctly expressed by calling `.flat_map(..)` \
|
||||
and filtering by returning `iter::empty()`";
|
||||
span_lint_and_help(cx, FILTER_MAP, expr.span, msg, hint);
|
||||
span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3260,6 +3266,7 @@ fn lint_suspicious_map(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) {
|
|||
SUSPICIOUS_MAP,
|
||||
expr.span,
|
||||
"this call to `map()` won't have an effect on the call to `count()`",
|
||||
None,
|
||||
"make sure you did not confuse `map` with `filter` or `for_each`",
|
||||
);
|
||||
}
|
||||
|
@ -3640,7 +3647,7 @@ fn lint_filetype_is_file(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &
|
|||
}
|
||||
let lint_msg = format!("`{}FileType::is_file()` only {} regular files", lint_unary, verb);
|
||||
let help_msg = format!("use `{}FileType::is_dir()` instead", help_unary);
|
||||
span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, &help_msg);
|
||||
span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg);
|
||||
}
|
||||
|
||||
fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
|
||||
|
|
|
@ -313,6 +313,7 @@ impl EarlyLintPass for MiscEarlyLints {
|
|||
UNNEEDED_FIELD_PATTERN,
|
||||
pat.span,
|
||||
"All the struct fields are matched to a wildcard pattern, consider using `..`.",
|
||||
None,
|
||||
&format!("Try with `{} {{ .. }}` instead", type_name),
|
||||
);
|
||||
return;
|
||||
|
@ -348,6 +349,7 @@ impl EarlyLintPass for MiscEarlyLints {
|
|||
field.span,
|
||||
"You matched a field with a wildcard pattern. Consider using `..` \
|
||||
instead",
|
||||
None,
|
||||
&format!("Try with `{} {{ {}, .. }}`", type_name, normal[..].join(", ")),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -304,6 +304,7 @@ fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str,
|
|||
NEEDLESS_CONTINUE,
|
||||
expr.span,
|
||||
message,
|
||||
None,
|
||||
&format!("{}\n{}", header, snip),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ impl EarlyLintPass for OptionEnvUnwrap {
|
|||
OPTION_ENV_UNWRAP,
|
||||
expr.span,
|
||||
"this will panic at run-time if the environment variable doesn't exist at compile-time",
|
||||
None,
|
||||
"consider using the `env!` macro instead"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
use crate::utils::ptr::get_spans;
|
||||
use crate::utils::{
|
||||
is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then,
|
||||
walk_ptrs_hir_ty,
|
||||
is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_sugg,
|
||||
span_lint_and_then, walk_ptrs_hir_ty,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -234,19 +234,14 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_
|
|||
then {
|
||||
let replacement = snippet_opt(cx, inner.span);
|
||||
if let Some(r) = replacement {
|
||||
span_lint_and_then(
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"using a reference to `Cow` is not recommended.",
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
arg.span,
|
||||
"change this to",
|
||||
"&".to_owned() + &r,
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
},
|
||||
"change this to",
|
||||
"&".to_owned() + &r,
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,7 +208,7 @@ fn check_regex<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>, utf8:
|
|||
match parser.parse(r) {
|
||||
Ok(r) => {
|
||||
if let Some(repl) = is_trivial_regex(&r) {
|
||||
span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", repl);
|
||||
span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl);
|
||||
}
|
||||
},
|
||||
Err(regex_syntax::Error::Parse(e)) => {
|
||||
|
@ -236,7 +236,7 @@ fn check_regex<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>, utf8:
|
|||
match parser.parse(&r) {
|
||||
Ok(r) => {
|
||||
if let Some(repl) = is_trivial_regex(&r) {
|
||||
span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", repl);
|
||||
span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl);
|
||||
}
|
||||
},
|
||||
Err(regex_syntax::Error::Parse(e)) => {
|
||||
|
|
|
@ -8,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
|
|||
use rustc_span::source_map::Span;
|
||||
use rustc_span::BytePos;
|
||||
|
||||
use crate::utils::{in_macro, match_path_ast, snippet_opt, span_lint_and_then};
|
||||
use crate::utils::{in_macro, match_path_ast, snippet_opt, span_lint_and_sugg, span_lint_and_then};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for return statements at the end of a block.
|
||||
|
@ -162,24 +162,26 @@ impl Return {
|
|||
},
|
||||
None => match replacement {
|
||||
RetReplacement::Empty => {
|
||||
span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
|
||||
diag.span_suggestion(
|
||||
ret_span,
|
||||
"remove `return`",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
});
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
NEEDLESS_RETURN,
|
||||
ret_span,
|
||||
"unneeded `return` statement",
|
||||
"remove `return`",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
RetReplacement::Block => {
|
||||
span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
|
||||
diag.span_suggestion(
|
||||
ret_span,
|
||||
"replace `return` with an empty block",
|
||||
"{}".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
});
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
NEEDLESS_RETURN,
|
||||
ret_span,
|
||||
"unneeded `return` statement",
|
||||
"replace `return` with an empty block",
|
||||
"{}".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -259,14 +261,15 @@ impl EarlyLintPass for Return {
|
|||
} else {
|
||||
(ty.span, Applicability::MaybeIncorrect)
|
||||
};
|
||||
span_lint_and_then(cx, UNUSED_UNIT, rspan, "unneeded unit return type", |diag| {
|
||||
diag.span_suggestion(
|
||||
rspan,
|
||||
"remove the `-> ()`",
|
||||
String::new(),
|
||||
appl,
|
||||
);
|
||||
});
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNUSED_UNIT,
|
||||
rspan,
|
||||
"unneeded unit return type",
|
||||
"remove the `-> ()`",
|
||||
String::new(),
|
||||
appl,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -279,14 +282,15 @@ impl EarlyLintPass for Return {
|
|||
if is_unit_expr(expr) && !stmt.span.from_expansion();
|
||||
then {
|
||||
let sp = expr.span;
|
||||
span_lint_and_then(cx, UNUSED_UNIT, sp, "unneeded unit expression", |diag| {
|
||||
diag.span_suggestion(
|
||||
sp,
|
||||
"remove the final `()`",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
});
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNUSED_UNIT,
|
||||
sp,
|
||||
"unneeded unit expression",
|
||||
"remove the final `()`",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -295,14 +299,15 @@ impl EarlyLintPass for Return {
|
|||
match e.kind {
|
||||
ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => {
|
||||
if is_unit_expr(expr) && !expr.span.from_expansion() {
|
||||
span_lint_and_then(cx, UNUSED_UNIT, expr.span, "unneeded `()`", |diag| {
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"remove the `()`",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
});
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNUSED_UNIT,
|
||||
expr.span,
|
||||
"unneeded `()`",
|
||||
"remove the `()`",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
|
|
|
@ -76,6 +76,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TraitBounds {
|
|||
TYPE_REPETITION_IN_BOUNDS,
|
||||
p.span,
|
||||
"this type has already been used as a bound predicate",
|
||||
None,
|
||||
&hint_string,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::utils::{
|
||||
is_normalizable, last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then, sugg,
|
||||
is_normalizable, last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_sugg,
|
||||
span_lint_and_then, sugg,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
|
@ -441,24 +442,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
|
|||
""
|
||||
};
|
||||
|
||||
span_lint_and_then(
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
TRANSMUTE_BYTES_TO_STR,
|
||||
e.span,
|
||||
&format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
e.span,
|
||||
"consider using",
|
||||
format!(
|
||||
"std::str::from_utf8{}({}).unwrap()",
|
||||
postfix,
|
||||
snippet(cx, args[0].span, ".."),
|
||||
),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
)
|
||||
"consider using",
|
||||
format!(
|
||||
"std::str::from_utf8{}({}).unwrap()",
|
||||
postfix,
|
||||
snippet(cx, args[0].span, ".."),
|
||||
),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
} else {
|
||||
if cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty) {
|
||||
span_lint_and_then(
|
||||
|
|
|
@ -343,6 +343,7 @@ impl Types {
|
|||
BOX_VEC,
|
||||
hir_ty.span,
|
||||
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
|
||||
None,
|
||||
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.",
|
||||
);
|
||||
return; // don't recurse into the type
|
||||
|
@ -437,6 +438,7 @@ impl Types {
|
|||
LINKEDLIST,
|
||||
hir_ty.span,
|
||||
"I see you're using a LinkedList! Perhaps you meant some other data structure?",
|
||||
None,
|
||||
"a `VecDeque` might work",
|
||||
);
|
||||
return; // don't recurse into the type
|
||||
|
@ -1900,7 +1902,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AbsurdExtremeComparisons {
|
|||
conclusion
|
||||
);
|
||||
|
||||
span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, &help);
|
||||
span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ impl LateLintPass<'_, '_> for UnnamedAddress {
|
|||
VTABLE_ADDRESS_COMPARISONS,
|
||||
expr.span,
|
||||
"comparing trait object pointers compares a non-unique vtable address",
|
||||
None,
|
||||
"consider extracting and comparing data pointers only",
|
||||
);
|
||||
}
|
||||
|
@ -109,6 +110,7 @@ impl LateLintPass<'_, '_> for UnnamedAddress {
|
|||
VTABLE_ADDRESS_COMPARISONS,
|
||||
expr.span,
|
||||
"comparing trait object pointers compares a non-unique vtable address",
|
||||
None,
|
||||
"consider extracting and comparing data pointers only",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedSelf {
|
|||
UNUSED_SELF,
|
||||
self_param.span,
|
||||
"unused `self` argument",
|
||||
None,
|
||||
"consider refactoring to a associated function",
|
||||
);
|
||||
return;
|
||||
|
|
|
@ -62,10 +62,21 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
|
|||
/// |
|
||||
/// = help: Consider using `f64::NAN` if you would like a constant representing NaN
|
||||
/// ```
|
||||
pub fn span_lint_and_help<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) {
|
||||
pub fn span_lint_and_help<'a, T: LintContext>(
|
||||
cx: &'a T,
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
msg: &str,
|
||||
help_span: Option<Span>,
|
||||
help: &str,
|
||||
) {
|
||||
cx.struct_span_lint(lint, span, |diag| {
|
||||
let mut diag = diag.build(msg);
|
||||
diag.help(help);
|
||||
if let Some(help_span) = help_span {
|
||||
diag.span_help(help_span, help);
|
||||
} else {
|
||||
diag.help(help);
|
||||
}
|
||||
docs_link(&mut diag, lint);
|
||||
diag.emit();
|
||||
});
|
||||
|
@ -97,15 +108,15 @@ pub fn span_lint_and_note<'a, T: LintContext>(
|
|||
lint: &'static Lint,
|
||||
span: Span,
|
||||
msg: &str,
|
||||
note_span: Span,
|
||||
note_span: Option<Span>,
|
||||
note: &str,
|
||||
) {
|
||||
cx.struct_span_lint(lint, span, |diag| {
|
||||
let mut diag = diag.build(msg);
|
||||
if note_span == span {
|
||||
diag.note(note);
|
||||
} else {
|
||||
if let Some(note_span) = note_span {
|
||||
diag.span_note(note_span, note);
|
||||
} else {
|
||||
diag.note(note);
|
||||
}
|
||||
docs_link(&mut diag, lint);
|
||||
diag.emit();
|
||||
|
@ -166,6 +177,7 @@ pub fn span_lint_hir_and_then(
|
|||
/// |
|
||||
/// = note: `-D fold-any` implied by `-D warnings`
|
||||
/// ```
|
||||
#[allow(clippy::collapsible_span_lint_calls)]
|
||||
pub fn span_lint_and_sugg<'a, T: LintContext>(
|
||||
cx: &'a T,
|
||||
lint: &'static Lint,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::utils::SpanlessEq;
|
||||
use crate::utils::{
|
||||
is_expn_of, match_def_path, match_type, method_calls, paths, span_lint, span_lint_and_help, span_lint_and_sugg,
|
||||
walk_ptrs_ty,
|
||||
is_expn_of, match_def_path, match_qpath, match_type, method_calls, paths, snippet, span_lint, span_lint_and_help,
|
||||
span_lint_and_sugg, walk_ptrs_ty,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, Name, NodeId};
|
||||
|
@ -10,13 +11,15 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Path, Ty, TyKind};
|
||||
use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Path, StmtKind, Ty, TyKind};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::source_map::{Span, Spanned};
|
||||
use rustc_span::symbol::SymbolStr;
|
||||
|
||||
use std::borrow::{Borrow, Cow};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for various things we like to keep tidy in clippy.
|
||||
///
|
||||
|
@ -142,6 +145,67 @@ declare_clippy_lint! {
|
|||
"found 'default lint description' in a lint declaration"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Lints `span_lint_and_then` function calls, where the
|
||||
/// closure argument has only one statement and that statement is a method
|
||||
/// call to `span_suggestion`, `span_help`, `span_note` (using the same
|
||||
/// span), `help` or `note`.
|
||||
///
|
||||
/// These usages of `span_lint_and_then` should be replaced with one of the
|
||||
/// wrapper functions `span_lint_and_sugg`, span_lint_and_help`, or
|
||||
/// `span_lint_and_note`.
|
||||
///
|
||||
/// **Why is this bad?** Using the wrapper `span_lint_and_*` functions, is more
|
||||
/// convenient, readable and less error prone.
|
||||
///
|
||||
/// **Known problems:** None
|
||||
///
|
||||
/// *Example:**
|
||||
/// Bad:
|
||||
/// ```rust,ignore
|
||||
/// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
|
||||
/// diag.span_suggestion(
|
||||
/// expr.span,
|
||||
/// help_msg,
|
||||
/// sugg.to_string(),
|
||||
/// Applicability::MachineApplicable,
|
||||
/// );
|
||||
/// });
|
||||
/// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
|
||||
/// diag.span_help(expr.span, help_msg);
|
||||
/// });
|
||||
/// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
|
||||
/// diag.help(help_msg);
|
||||
/// });
|
||||
/// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
|
||||
/// diag.span_note(expr.span, note_msg);
|
||||
/// });
|
||||
/// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
|
||||
/// diag.note(note_msg);
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// Good:
|
||||
/// ```rust,ignore
|
||||
/// span_lint_and_sugg(
|
||||
/// cx,
|
||||
/// TEST_LINT,
|
||||
/// expr.span,
|
||||
/// lint_msg,
|
||||
/// help_msg,
|
||||
/// sugg.to_string(),
|
||||
/// Applicability::MachineApplicable,
|
||||
/// );
|
||||
/// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg);
|
||||
/// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg);
|
||||
/// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg);
|
||||
/// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg);
|
||||
/// ```
|
||||
pub COLLAPSIBLE_SPAN_LINT_CALLS,
|
||||
internal,
|
||||
"found collapsible `span_lint_and_then` calls"
|
||||
}
|
||||
|
||||
declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
|
||||
|
||||
impl EarlyLintPass for ClippyLintsInternal {
|
||||
|
@ -194,9 +258,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass {
|
|||
if_chain! {
|
||||
if let ExprKind::AddrOf(_, _, ref inner_exp) = expr.kind;
|
||||
if let ExprKind::Struct(_, ref fields, _) = inner_exp.kind;
|
||||
let field = fields.iter()
|
||||
.find(|f| f.ident.as_str() == "desc")
|
||||
.expect("lints must have a description field");
|
||||
let field = fields
|
||||
.iter()
|
||||
.find(|f| f.ident.as_str() == "desc")
|
||||
.expect("lints must have a description field");
|
||||
if let ExprKind::Lit(Spanned {
|
||||
node: LitKind::Str(ref sym, _),
|
||||
..
|
||||
|
@ -339,6 +404,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CompilerLintFunctions {
|
|||
COMPILER_LINT_FUNCTIONS,
|
||||
path.ident.span,
|
||||
"usage of a compiler lint function",
|
||||
None,
|
||||
&format!("please use the Clippy variant of this function: `{}`", sugg),
|
||||
);
|
||||
}
|
||||
|
@ -391,3 +457,184 @@ fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {
|
|||
FnKind::Closure(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]);
|
||||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CollapsibleCalls {
|
||||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||
if_chain! {
|
||||
if let ExprKind::Call(ref func, ref and_then_args) = expr.kind;
|
||||
if let ExprKind::Path(ref path) = func.kind;
|
||||
if match_qpath(path, &["span_lint_and_then"]);
|
||||
if and_then_args.len() == 5;
|
||||
if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind;
|
||||
let body = cx.tcx.hir().body(*body_id);
|
||||
if let ExprKind::Block(block, _) = &body.value.kind;
|
||||
let stmts = &block.stmts;
|
||||
if stmts.len() == 1 && block.expr.is_none();
|
||||
if let StmtKind::Semi(only_expr) = &stmts[0].kind;
|
||||
if let ExprKind::MethodCall(ref ps, _, ref span_call_args) = &only_expr.kind;
|
||||
let and_then_snippets = get_and_then_snippets(cx, and_then_args);
|
||||
let mut sle = SpanlessEq::new(cx).ignore_fn();
|
||||
then {
|
||||
match &*ps.ident.as_str() {
|
||||
"span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
|
||||
suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args));
|
||||
},
|
||||
"span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
|
||||
let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
|
||||
suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
|
||||
},
|
||||
"span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
|
||||
let note_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
|
||||
suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
|
||||
},
|
||||
"help" => {
|
||||
let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
|
||||
suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false);
|
||||
}
|
||||
"note" => {
|
||||
let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
|
||||
suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AndThenSnippets<'a> {
|
||||
cx: Cow<'a, str>,
|
||||
lint: Cow<'a, str>,
|
||||
span: Cow<'a, str>,
|
||||
msg: Cow<'a, str>,
|
||||
}
|
||||
|
||||
fn get_and_then_snippets<'a, 'hir>(
|
||||
cx: &LateContext<'_, '_>,
|
||||
and_then_snippets: &'hir [Expr<'hir>],
|
||||
) -> AndThenSnippets<'a> {
|
||||
let cx_snippet = snippet(cx, and_then_snippets[0].span, "cx");
|
||||
let lint_snippet = snippet(cx, and_then_snippets[1].span, "..");
|
||||
let span_snippet = snippet(cx, and_then_snippets[2].span, "span");
|
||||
let msg_snippet = snippet(cx, and_then_snippets[3].span, r#""...""#);
|
||||
|
||||
AndThenSnippets {
|
||||
cx: cx_snippet,
|
||||
lint: lint_snippet,
|
||||
span: span_snippet,
|
||||
msg: msg_snippet,
|
||||
}
|
||||
}
|
||||
|
||||
struct SpanSuggestionSnippets<'a> {
|
||||
help: Cow<'a, str>,
|
||||
sugg: Cow<'a, str>,
|
||||
applicability: Cow<'a, str>,
|
||||
}
|
||||
|
||||
fn span_suggestion_snippets<'a, 'hir>(
|
||||
cx: &LateContext<'_, '_>,
|
||||
span_call_args: &'hir [Expr<'hir>],
|
||||
) -> SpanSuggestionSnippets<'a> {
|
||||
let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
|
||||
let sugg_snippet = snippet(cx, span_call_args[3].span, "..");
|
||||
let applicability_snippet = snippet(cx, span_call_args[4].span, "Applicability::MachineApplicable");
|
||||
|
||||
SpanSuggestionSnippets {
|
||||
help: help_snippet,
|
||||
sugg: sugg_snippet,
|
||||
applicability: applicability_snippet,
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_suggestion(
|
||||
cx: &LateContext<'_, '_>,
|
||||
expr: &Expr<'_>,
|
||||
and_then_snippets: &AndThenSnippets<'_>,
|
||||
span_suggestion_snippets: &SpanSuggestionSnippets<'_>,
|
||||
) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
COLLAPSIBLE_SPAN_LINT_CALLS,
|
||||
expr.span,
|
||||
"this call is collapsible",
|
||||
"collapse into",
|
||||
format!(
|
||||
"span_lint_and_sugg({}, {}, {}, {}, {}, {}, {})",
|
||||
and_then_snippets.cx,
|
||||
and_then_snippets.lint,
|
||||
and_then_snippets.span,
|
||||
and_then_snippets.msg,
|
||||
span_suggestion_snippets.help,
|
||||
span_suggestion_snippets.sugg,
|
||||
span_suggestion_snippets.applicability
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
fn suggest_help(
|
||||
cx: &LateContext<'_, '_>,
|
||||
expr: &Expr<'_>,
|
||||
and_then_snippets: &AndThenSnippets<'_>,
|
||||
help: &str,
|
||||
with_span: bool,
|
||||
) {
|
||||
let option_span = if with_span {
|
||||
format!("Some({})", and_then_snippets.span)
|
||||
} else {
|
||||
"None".to_string()
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
COLLAPSIBLE_SPAN_LINT_CALLS,
|
||||
expr.span,
|
||||
"this call is collapsible",
|
||||
"collapse into",
|
||||
format!(
|
||||
"span_lint_and_help({}, {}, {}, {}, {}, {})",
|
||||
and_then_snippets.cx,
|
||||
and_then_snippets.lint,
|
||||
and_then_snippets.span,
|
||||
and_then_snippets.msg,
|
||||
&option_span,
|
||||
help
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
fn suggest_note(
|
||||
cx: &LateContext<'_, '_>,
|
||||
expr: &Expr<'_>,
|
||||
and_then_snippets: &AndThenSnippets<'_>,
|
||||
note: &str,
|
||||
with_span: bool,
|
||||
) {
|
||||
let note_span = if with_span {
|
||||
format!("Some({})", and_then_snippets.span)
|
||||
} else {
|
||||
"None".to_string()
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
COLLAPSIBLE_SPAN_LINT_CALLS,
|
||||
expr.span,
|
||||
"this call is collspible",
|
||||
"collapse into",
|
||||
format!(
|
||||
"span_lint_and_note({}, {}, {}, {}, {}, {})",
|
||||
and_then_snippets.cx,
|
||||
and_then_snippets.lint,
|
||||
and_then_snippets.span,
|
||||
and_then_snippets.msg,
|
||||
note_span,
|
||||
note
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VerboseFileReads {
|
|||
VERBOSE_FILE_READS,
|
||||
expr.span,
|
||||
"use of `File::read_to_end`",
|
||||
None,
|
||||
"consider using `fs::read` instead",
|
||||
);
|
||||
} else if is_file_read_to_string(cx, expr) {
|
||||
|
@ -48,6 +49,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VerboseFileReads {
|
|||
VERBOSE_FILE_READS,
|
||||
expr.span,
|
||||
"use of `File::read_to_string`",
|
||||
None,
|
||||
"consider using `fs::read_to_string` instead",
|
||||
)
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ZeroDiv {
|
|||
ZERO_DIVIDED_BY_ZERO,
|
||||
expr.span,
|
||||
"constant division of `0.0` with `0.0` will always result in NaN",
|
||||
None,
|
||||
&format!(
|
||||
"Consider using `{}::NAN` if you would like a constant representing NaN",
|
||||
float_type,
|
||||
|
|
|
@ -265,6 +265,7 @@ impl EarlyLintPass for FooFunctions {
|
|||
FOO_FUNCTIONS,
|
||||
span,
|
||||
"function named `foo`",
|
||||
None,
|
||||
"consider using a more meaningful name"
|
||||
);
|
||||
}
|
||||
|
@ -296,6 +297,7 @@ impl EarlyLintPass for FooFunctions {
|
|||
FOO_FUNCTIONS,
|
||||
span,
|
||||
"function named `foo`",
|
||||
None,
|
||||
"consider using a more meaningful name"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
// run-rustfix
|
||||
#![deny(clippy::internal)]
|
||||
#![feature(rustc_private)]
|
||||
|
||||
extern crate rustc_ast;
|
||||
extern crate rustc_errors;
|
||||
extern crate rustc_lint;
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
|
||||
use rustc_ast::ast::Expr;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
|
||||
where
|
||||
F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
|
||||
{
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn span_lint_and_help<'a, T: LintContext>(
|
||||
cx: &'a T,
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
msg: &str,
|
||||
option_span: Option<Span>,
|
||||
help: &str,
|
||||
) {
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn span_lint_and_note<'a, T: LintContext>(
|
||||
cx: &'a T,
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
msg: &str,
|
||||
note_span: Option<Span>,
|
||||
note: &str,
|
||||
) {
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn span_lint_and_sugg<'a, T: LintContext>(
|
||||
cx: &'a T,
|
||||
lint: &'static Lint,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
help: &str,
|
||||
sugg: String,
|
||||
applicability: Applicability,
|
||||
) {
|
||||
}
|
||||
|
||||
declare_tool_lint! {
|
||||
pub clippy::TEST_LINT,
|
||||
Warn,
|
||||
"",
|
||||
report_in_external_macro: true
|
||||
}
|
||||
|
||||
declare_lint_pass!(Pass => [TEST_LINT]);
|
||||
|
||||
impl EarlyLintPass for Pass {
|
||||
fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
|
||||
let lint_msg = "lint message";
|
||||
let help_msg = "help message";
|
||||
let note_msg = "note message";
|
||||
let sugg = "new_call()";
|
||||
let predicate = true;
|
||||
|
||||
span_lint_and_sugg(cx, TEST_LINT, expr.span, lint_msg, help_msg, sugg.to_string(), Applicability::MachineApplicable);
|
||||
span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg);
|
||||
span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg);
|
||||
span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg);
|
||||
span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg);
|
||||
|
||||
// This expr shouldn't trigger this lint.
|
||||
span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
|
||||
db.note(note_msg);
|
||||
if predicate {
|
||||
db.note(note_msg);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,101 @@
|
|||
// run-rustfix
|
||||
#![deny(clippy::internal)]
|
||||
#![feature(rustc_private)]
|
||||
|
||||
extern crate rustc_ast;
|
||||
extern crate rustc_errors;
|
||||
extern crate rustc_lint;
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
|
||||
use rustc_ast::ast::Expr;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
|
||||
where
|
||||
F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
|
||||
{
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn span_lint_and_help<'a, T: LintContext>(
|
||||
cx: &'a T,
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
msg: &str,
|
||||
option_span: Option<Span>,
|
||||
help: &str,
|
||||
) {
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn span_lint_and_note<'a, T: LintContext>(
|
||||
cx: &'a T,
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
msg: &str,
|
||||
note_span: Option<Span>,
|
||||
note: &str,
|
||||
) {
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn span_lint_and_sugg<'a, T: LintContext>(
|
||||
cx: &'a T,
|
||||
lint: &'static Lint,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
help: &str,
|
||||
sugg: String,
|
||||
applicability: Applicability,
|
||||
) {
|
||||
}
|
||||
|
||||
declare_tool_lint! {
|
||||
pub clippy::TEST_LINT,
|
||||
Warn,
|
||||
"",
|
||||
report_in_external_macro: true
|
||||
}
|
||||
|
||||
declare_lint_pass!(Pass => [TEST_LINT]);
|
||||
|
||||
impl EarlyLintPass for Pass {
|
||||
fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
|
||||
let lint_msg = "lint message";
|
||||
let help_msg = "help message";
|
||||
let note_msg = "note message";
|
||||
let sugg = "new_call()";
|
||||
let predicate = true;
|
||||
|
||||
span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
|
||||
db.span_suggestion(expr.span, help_msg, sugg.to_string(), Applicability::MachineApplicable);
|
||||
});
|
||||
span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
|
||||
db.span_help(expr.span, help_msg);
|
||||
});
|
||||
span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
|
||||
db.help(help_msg);
|
||||
});
|
||||
span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
|
||||
db.span_note(expr.span, note_msg);
|
||||
});
|
||||
span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
|
||||
db.note(note_msg);
|
||||
});
|
||||
|
||||
// This expr shouldn't trigger this lint.
|
||||
span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
|
||||
db.note(note_msg);
|
||||
if predicate {
|
||||
db.note(note_msg);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,49 @@
|
|||
error: this call is collapsible
|
||||
--> $DIR/collapsible_span_lint_calls.rs:75:9
|
||||
|
|
||||
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
|
||||
LL | | db.span_suggestion(expr.span, help_msg, sugg.to_string(), Applicability::MachineApplicable);
|
||||
LL | | });
|
||||
| |__________^ help: collapse into: `span_lint_and_sugg(cx, TEST_LINT, expr.span, lint_msg, help_msg, sugg.to_string(), Applicability::MachineApplicable)`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/collapsible_span_lint_calls.rs:2:9
|
||||
|
|
||||
LL | #![deny(clippy::internal)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
= note: `#[deny(clippy::collapsible_span_lint_calls)]` implied by `#[deny(clippy::internal)]`
|
||||
|
||||
error: this call is collapsible
|
||||
--> $DIR/collapsible_span_lint_calls.rs:78:9
|
||||
|
|
||||
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
|
||||
LL | | db.span_help(expr.span, help_msg);
|
||||
LL | | });
|
||||
| |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg)`
|
||||
|
||||
error: this call is collapsible
|
||||
--> $DIR/collapsible_span_lint_calls.rs:81:9
|
||||
|
|
||||
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
|
||||
LL | | db.help(help_msg);
|
||||
LL | | });
|
||||
| |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg)`
|
||||
|
||||
error: this call is collspible
|
||||
--> $DIR/collapsible_span_lint_calls.rs:84:9
|
||||
|
|
||||
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
|
||||
LL | | db.span_note(expr.span, note_msg);
|
||||
LL | | });
|
||||
| |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg)`
|
||||
|
||||
error: this call is collspible
|
||||
--> $DIR/collapsible_span_lint_calls.rs:87:9
|
||||
|
|
||||
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
|
||||
LL | | db.note(note_msg);
|
||||
LL | | });
|
||||
| |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg)`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
|
@ -5,11 +5,7 @@ LL | enum Empty {}
|
|||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::empty-enum` implied by `-D warnings`
|
||||
help: consider using the uninhabited type `!` (never type) or a wrapper around it to introduce a type which can't be instantiated
|
||||
--> $DIR/empty_enum.rs:4:1
|
||||
|
|
||||
LL | enum Empty {}
|
||||
| ^^^^^^^^^^^^^
|
||||
= help: consider using the uninhabited type `!` (never type) or a wrapper around it to introduce a type which can't be instantiated
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
Loading…
Reference in New Issue