mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-10 15:14:29 +00:00
Add needless_late_init
lint
This commit is contained in:
parent
81f37a8150
commit
3957244120
18 changed files with 838 additions and 27 deletions
|
@ -3033,6 +3033,7 @@ Released 2018-09-13
|
|||
[`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue
|
||||
[`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main
|
||||
[`needless_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each
|
||||
[`needless_late_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_late_init
|
||||
[`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
|
||||
[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
|
||||
[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
|
||||
|
|
|
@ -206,6 +206,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
|||
LintId::of(needless_bool::BOOL_COMPARISON),
|
||||
LintId::of(needless_bool::NEEDLESS_BOOL),
|
||||
LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
|
||||
LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
|
||||
LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF),
|
||||
LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
|
||||
LintId::of(needless_update::NEEDLESS_UPDATE),
|
||||
|
|
|
@ -362,6 +362,7 @@ store.register_lints(&[
|
|||
needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
|
||||
needless_continue::NEEDLESS_CONTINUE,
|
||||
needless_for_each::NEEDLESS_FOR_EACH,
|
||||
needless_late_init::NEEDLESS_LATE_INIT,
|
||||
needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF,
|
||||
needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
|
||||
needless_question_mark::NEEDLESS_QUESTION_MARK,
|
||||
|
|
|
@ -82,6 +82,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
|
|||
LintId::of(misc_early::REDUNDANT_PATTERN),
|
||||
LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
|
||||
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
|
||||
LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
|
||||
LintId::of(neg_multiply::NEG_MULTIPLY),
|
||||
LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
|
||||
LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
|
||||
|
|
|
@ -299,6 +299,7 @@ mod needless_bool;
|
|||
mod needless_borrowed_ref;
|
||||
mod needless_continue;
|
||||
mod needless_for_each;
|
||||
mod needless_late_init;
|
||||
mod needless_option_as_deref;
|
||||
mod needless_pass_by_value;
|
||||
mod needless_question_mark;
|
||||
|
@ -851,6 +852,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(move || Box::new(format_args::FormatArgs));
|
||||
store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
|
||||
store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
|
||||
store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
|
345
clippy_lints/src/needless_late_init.rs
Normal file
345
clippy_lints/src/needless_late_init.rs
Normal file
|
@ -0,0 +1,345 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::path_to_local;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::visitors::{expr_visitor, is_local_used};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for late initializations that can be replaced by a let statement
|
||||
/// with an initializer.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Assigning in the let statement is less repetitive.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let a;
|
||||
/// a = 1;
|
||||
///
|
||||
/// let b;
|
||||
/// match 3 {
|
||||
/// 0 => b = "zero",
|
||||
/// 1 => b = "one",
|
||||
/// _ => b = "many",
|
||||
/// }
|
||||
///
|
||||
/// let c;
|
||||
/// if true {
|
||||
/// c = 1;
|
||||
/// } else {
|
||||
/// c = -1;
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let a = 1;
|
||||
///
|
||||
/// let b = match 3 {
|
||||
/// 0 => "zero",
|
||||
/// 1 => "one",
|
||||
/// _ => "many",
|
||||
/// };
|
||||
///
|
||||
/// let c = if true {
|
||||
/// 1
|
||||
/// } else {
|
||||
/// -1
|
||||
/// };
|
||||
/// ```
|
||||
#[clippy::version = "1.58.0"]
|
||||
pub NEEDLESS_LATE_INIT,
|
||||
style,
|
||||
"late initializations that can be replaced by a let statement with an initializer"
|
||||
}
|
||||
declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]);
|
||||
|
||||
fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool {
|
||||
let mut seen = false;
|
||||
expr_visitor(cx, |expr| {
|
||||
if let ExprKind::Assign(..) = expr.kind {
|
||||
seen = true;
|
||||
}
|
||||
|
||||
!seen
|
||||
})
|
||||
.visit_stmt(stmt);
|
||||
|
||||
seen
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LocalAssign {
|
||||
lhs_id: HirId,
|
||||
lhs_span: Span,
|
||||
rhs_span: Span,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl LocalAssign {
|
||||
fn from_expr(expr: &Expr<'_>, span: Span) -> Option<Self> {
|
||||
if let ExprKind::Assign(lhs, rhs, _) = expr.kind {
|
||||
if lhs.span.from_expansion() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Self {
|
||||
lhs_id: path_to_local(lhs)?,
|
||||
lhs_span: lhs.span,
|
||||
rhs_span: rhs.span.source_callsite(),
|
||||
span,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, binding_id: HirId) -> Option<LocalAssign> {
|
||||
let assign = match expr.kind {
|
||||
ExprKind::Block(Block { expr: Some(expr), .. }, _) => Self::from_expr(expr, expr.span),
|
||||
ExprKind::Block(block, _) => {
|
||||
if_chain! {
|
||||
if let Some((last, other_stmts)) = block.stmts.split_last();
|
||||
if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = last.kind;
|
||||
|
||||
let assign = Self::from_expr(expr, last.span)?;
|
||||
|
||||
// avoid visiting if not needed
|
||||
if assign.lhs_id == binding_id;
|
||||
if other_stmts.iter().all(|stmt| !contains_assign_expr(cx, stmt));
|
||||
|
||||
then {
|
||||
Some(assign)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
},
|
||||
ExprKind::Assign(..) => Self::from_expr(expr, expr.span),
|
||||
_ => None,
|
||||
}?;
|
||||
|
||||
if assign.lhs_id == binding_id {
|
||||
Some(assign)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn assignment_suggestions<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
binding_id: HirId,
|
||||
exprs: impl IntoIterator<Item = &'tcx Expr<'tcx>>,
|
||||
) -> Option<(Applicability, Vec<(Span, String)>)> {
|
||||
let mut assignments = Vec::new();
|
||||
|
||||
for expr in exprs {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
|
||||
if ty.is_never() {
|
||||
continue;
|
||||
}
|
||||
if !ty.is_unit() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let assign = LocalAssign::new(cx, expr, binding_id)?;
|
||||
|
||||
assignments.push(assign);
|
||||
}
|
||||
|
||||
let suggestions = assignments
|
||||
.into_iter()
|
||||
.map(|assignment| Some((assignment.span, snippet_opt(cx, assignment.rhs_span)?)))
|
||||
.collect::<Option<Vec<(Span, String)>>>()?;
|
||||
|
||||
let applicability = if suggestions.len() > 1 {
|
||||
// multiple suggestions don't work with rustfix in multipart_suggest
|
||||
// https://github.com/rust-lang/rustfix/issues/141
|
||||
Applicability::Unspecified
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
Some((applicability, suggestions))
|
||||
}
|
||||
|
||||
struct Usage<'tcx> {
|
||||
stmt: &'tcx Stmt<'tcx>,
|
||||
expr: &'tcx Expr<'tcx>,
|
||||
needs_semi: bool,
|
||||
}
|
||||
|
||||
fn first_usage<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
binding_id: HirId,
|
||||
local_stmt_id: HirId,
|
||||
block: &'tcx Block<'tcx>,
|
||||
) -> Option<Usage<'tcx>> {
|
||||
block
|
||||
.stmts
|
||||
.iter()
|
||||
.skip_while(|stmt| stmt.hir_id != local_stmt_id)
|
||||
.skip(1)
|
||||
.find(|&stmt| is_local_used(cx, stmt, binding_id))
|
||||
.and_then(|stmt| match stmt.kind {
|
||||
StmtKind::Expr(expr) => Some(Usage {
|
||||
stmt,
|
||||
expr,
|
||||
needs_semi: true,
|
||||
}),
|
||||
StmtKind::Semi(expr) => Some(Usage {
|
||||
stmt,
|
||||
expr,
|
||||
needs_semi: false,
|
||||
}),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &Local<'_>) -> Option<String> {
|
||||
let span = local.span.with_hi(match local.ty {
|
||||
// let <pat>: <ty>;
|
||||
// ~~~~~~~~~~~~~~~
|
||||
Some(ty) => ty.span.hi(),
|
||||
// let <pat>;
|
||||
// ~~~~~~~~~
|
||||
None => local.pat.span.hi(),
|
||||
});
|
||||
|
||||
snippet_opt(cx, span)
|
||||
}
|
||||
|
||||
fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
local: &'tcx Local<'tcx>,
|
||||
local_stmt: &'tcx Stmt<'tcx>,
|
||||
block: &'tcx Block<'tcx>,
|
||||
binding_id: HirId,
|
||||
) -> Option<()> {
|
||||
let usage = first_usage(cx, binding_id, local_stmt.hir_id, block)?;
|
||||
let binding_name = cx.tcx.hir().opt_name(binding_id)?;
|
||||
let let_snippet = local_snippet_without_semicolon(cx, local)?;
|
||||
|
||||
match usage.expr.kind {
|
||||
ExprKind::Assign(..) => {
|
||||
let assign = LocalAssign::new(cx, usage.expr, binding_id)?;
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_LATE_INIT,
|
||||
local_stmt.span,
|
||||
"unneeded late initalization",
|
||||
|diag| {
|
||||
diag.tool_only_span_suggestion(
|
||||
local_stmt.span,
|
||||
"remove the local",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
||||
diag.span_suggestion(
|
||||
assign.lhs_span,
|
||||
&format!("declare `{}` here", binding_name),
|
||||
let_snippet,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
ExprKind::If(_, then_expr, Some(else_expr)) => {
|
||||
let (applicability, suggestions) = assignment_suggestions(cx, binding_id, [then_expr, else_expr])?;
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_LATE_INIT,
|
||||
local_stmt.span,
|
||||
"unneeded late initalization",
|
||||
|diag| {
|
||||
diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability);
|
||||
|
||||
diag.span_suggestion_verbose(
|
||||
usage.stmt.span.shrink_to_lo(),
|
||||
&format!("declare `{}` here", binding_name),
|
||||
format!("{} = ", let_snippet),
|
||||
applicability,
|
||||
);
|
||||
|
||||
diag.multipart_suggestion("remove the assignments from the branches", suggestions, applicability);
|
||||
|
||||
if usage.needs_semi {
|
||||
diag.span_suggestion(
|
||||
usage.stmt.span.shrink_to_hi(),
|
||||
"add a semicolon after the if expression",
|
||||
";".to_string(),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
ExprKind::Match(_, arms, MatchSource::Normal) => {
|
||||
let (applicability, suggestions) = assignment_suggestions(cx, binding_id, arms.iter().map(|arm| arm.body))?;
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_LATE_INIT,
|
||||
local_stmt.span,
|
||||
"unneeded late initalization",
|
||||
|diag| {
|
||||
diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability);
|
||||
|
||||
diag.span_suggestion_verbose(
|
||||
usage.stmt.span.shrink_to_lo(),
|
||||
&format!("declare `{}` here", binding_name),
|
||||
format!("{} = ", let_snippet),
|
||||
applicability,
|
||||
);
|
||||
|
||||
diag.multipart_suggestion("remove the assignments from the match arms", suggestions, applicability);
|
||||
|
||||
if usage.needs_semi {
|
||||
diag.span_suggestion(
|
||||
usage.stmt.span.shrink_to_hi(),
|
||||
"add a semicolon after the match expression",
|
||||
";".to_string(),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
impl LateLintPass<'tcx> for NeedlessLateInit {
|
||||
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
|
||||
let mut parents = cx.tcx.hir().parent_iter(local.hir_id);
|
||||
|
||||
if_chain! {
|
||||
if let Local {
|
||||
init: None,
|
||||
pat: &Pat {
|
||||
kind: PatKind::Binding(_, binding_id, _, None),
|
||||
..
|
||||
},
|
||||
source: LocalSource::Normal,
|
||||
..
|
||||
} = local;
|
||||
if let Some((_, Node::Stmt(local_stmt))) = parents.next();
|
||||
if let Some((_, Node::Block(block))) = parents.next();
|
||||
|
||||
then {
|
||||
check(cx, local, local_stmt, block, binding_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -164,12 +164,13 @@ fn check_unnecessary_operation(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
|
|||
if !&reduced.iter().any(|e| e.span.from_expansion());
|
||||
then {
|
||||
if let ExprKind::Index(..) = &expr.kind {
|
||||
let snippet;
|
||||
if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) {
|
||||
snippet = format!("assert!({}.len() > {});", &arr, &func);
|
||||
let snippet = if let (Some(arr), Some(func)) =
|
||||
(snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span))
|
||||
{
|
||||
format!("assert!({}.len() > {});", &arr, &func)
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
span_lint_hir_and_then(
|
||||
cx,
|
||||
UNNECESSARY_OPERATION,
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
error: unneeded late initalization
|
||||
--> $DIR/let_if_seq.rs:48:5
|
||||
|
|
||||
LL | let foo;
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::needless-late-init` implied by `-D warnings`
|
||||
help: declare `foo` here
|
||||
|
|
||||
LL | let foo = if f() {
|
||||
| +++++++++
|
||||
help: remove the assignments from the branches
|
||||
|
|
||||
LL | 0
|
||||
|
|
||||
help: add a semicolon after the if expression
|
||||
|
|
||||
LL | };
|
||||
| +
|
||||
|
||||
error: `if _ { .. } else { .. }` is an expression
|
||||
--> $DIR/let_if_seq.rs:65:5
|
||||
|
|
||||
|
@ -46,5 +66,26 @@ LL | | }
|
|||
|
|
||||
= note: you might not need `mut` at all
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: unneeded late initalization
|
||||
--> $DIR/let_if_seq.rs:78:5
|
||||
|
|
||||
LL | let quz;
|
||||
| ^^^^^^^^
|
||||
|
|
||||
help: declare `quz` here
|
||||
|
|
||||
LL | let quz = if f() {
|
||||
| +++++++++
|
||||
help: remove the assignments from the branches
|
||||
|
|
||||
LL ~ 42
|
||||
LL | } else {
|
||||
LL ~ 0
|
||||
|
|
||||
help: add a semicolon after the if expression
|
||||
|
|
||||
LL | };
|
||||
| +
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
|
@ -19,8 +19,7 @@ impl NotOrd {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let x;
|
||||
x = 2usize;
|
||||
let x = 2usize;
|
||||
min(1, max(3, x));
|
||||
min(max(3, x), 1);
|
||||
max(min(x, 1), 3);
|
||||
|
@ -35,9 +34,7 @@ fn main() {
|
|||
let y = 2isize;
|
||||
min(max(y, -1), 3);
|
||||
|
||||
let s;
|
||||
s = "Hello";
|
||||
|
||||
let s = "Hello";
|
||||
min("Apple", max("Zoo", s));
|
||||
max(min(s, "Apple"), "Zoo");
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: this `min`/`max` combination leads to constant result
|
||||
--> $DIR/min_max.rs:24:5
|
||||
--> $DIR/min_max.rs:23:5
|
||||
|
|
||||
LL | min(1, max(3, x));
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
@ -7,73 +7,73 @@ LL | min(1, max(3, x));
|
|||
= note: `-D clippy::min-max` implied by `-D warnings`
|
||||
|
||||
error: this `min`/`max` combination leads to constant result
|
||||
--> $DIR/min_max.rs:25:5
|
||||
--> $DIR/min_max.rs:24:5
|
||||
|
|
||||
LL | min(max(3, x), 1);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this `min`/`max` combination leads to constant result
|
||||
--> $DIR/min_max.rs:26:5
|
||||
--> $DIR/min_max.rs:25:5
|
||||
|
|
||||
LL | max(min(x, 1), 3);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this `min`/`max` combination leads to constant result
|
||||
--> $DIR/min_max.rs:27:5
|
||||
--> $DIR/min_max.rs:26:5
|
||||
|
|
||||
LL | max(3, min(x, 1));
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this `min`/`max` combination leads to constant result
|
||||
--> $DIR/min_max.rs:29:5
|
||||
--> $DIR/min_max.rs:28:5
|
||||
|
|
||||
LL | my_max(3, my_min(x, 1));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this `min`/`max` combination leads to constant result
|
||||
--> $DIR/min_max.rs:41:5
|
||||
--> $DIR/min_max.rs:38:5
|
||||
|
|
||||
LL | min("Apple", max("Zoo", s));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this `min`/`max` combination leads to constant result
|
||||
--> $DIR/min_max.rs:42:5
|
||||
--> $DIR/min_max.rs:39:5
|
||||
|
|
||||
LL | max(min(s, "Apple"), "Zoo");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this `min`/`max` combination leads to constant result
|
||||
--> $DIR/min_max.rs:47:5
|
||||
--> $DIR/min_max.rs:44:5
|
||||
|
|
||||
LL | x.min(1).max(3);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: this `min`/`max` combination leads to constant result
|
||||
--> $DIR/min_max.rs:48:5
|
||||
--> $DIR/min_max.rs:45:5
|
||||
|
|
||||
LL | x.max(3).min(1);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: this `min`/`max` combination leads to constant result
|
||||
--> $DIR/min_max.rs:49:5
|
||||
--> $DIR/min_max.rs:46:5
|
||||
|
|
||||
LL | f.max(3f32).min(1f32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this `min`/`max` combination leads to constant result
|
||||
--> $DIR/min_max.rs:55:5
|
||||
--> $DIR/min_max.rs:52:5
|
||||
|
|
||||
LL | max(x.min(1), 3);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this `min`/`max` combination leads to constant result
|
||||
--> $DIR/min_max.rs:58:5
|
||||
--> $DIR/min_max.rs:55:5
|
||||
|
|
||||
LL | s.max("Zoo").min("Apple");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this `min`/`max` combination leads to constant result
|
||||
--> $DIR/min_max.rs:59:5
|
||||
--> $DIR/min_max.rs:56:5
|
||||
|
|
||||
LL | s.min("Apple").max("Zoo");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
133
tests/ui/needless_late_init.rs
Normal file
133
tests/ui/needless_late_init.rs
Normal file
|
@ -0,0 +1,133 @@
|
|||
#![allow(unused)]
|
||||
|
||||
fn main() {
|
||||
let a;
|
||||
let n = 1;
|
||||
match n {
|
||||
1 => a = "one",
|
||||
_ => {
|
||||
a = "two";
|
||||
},
|
||||
}
|
||||
|
||||
let b;
|
||||
if n == 3 {
|
||||
b = "four";
|
||||
} else {
|
||||
b = "five"
|
||||
}
|
||||
|
||||
let c;
|
||||
if let Some(n) = Some(5) {
|
||||
c = n;
|
||||
} else {
|
||||
c = -50;
|
||||
}
|
||||
|
||||
let d;
|
||||
if true {
|
||||
let temp = 5;
|
||||
d = temp;
|
||||
} else {
|
||||
d = 15;
|
||||
}
|
||||
|
||||
let e;
|
||||
if true {
|
||||
e = format!("{} {}", a, b);
|
||||
} else {
|
||||
e = format!("{}", c);
|
||||
}
|
||||
|
||||
println!("{}", a);
|
||||
}
|
||||
|
||||
fn does_not_lint() {
|
||||
let z;
|
||||
if false {
|
||||
z = 1;
|
||||
}
|
||||
|
||||
let x;
|
||||
let y;
|
||||
if true {
|
||||
x = 1;
|
||||
} else {
|
||||
y = 1;
|
||||
}
|
||||
|
||||
let mut x;
|
||||
if true {
|
||||
x = 5;
|
||||
x = 10 / x;
|
||||
} else {
|
||||
x = 2;
|
||||
}
|
||||
|
||||
let x;
|
||||
let _ = match 1 {
|
||||
1 => x = 10,
|
||||
_ => x = 20,
|
||||
};
|
||||
|
||||
// using tuples would be possible, but not always preferable
|
||||
let x;
|
||||
let y;
|
||||
if true {
|
||||
x = 1;
|
||||
y = 2;
|
||||
} else {
|
||||
x = 3;
|
||||
y = 4;
|
||||
}
|
||||
|
||||
// could match with a smarter heuristic to avoid multiple assignments
|
||||
let x;
|
||||
if true {
|
||||
let mut y = 5;
|
||||
y = 6;
|
||||
x = y;
|
||||
} else {
|
||||
x = 2;
|
||||
}
|
||||
|
||||
let (x, y);
|
||||
if true {
|
||||
x = 1;
|
||||
} else {
|
||||
x = 2;
|
||||
}
|
||||
y = 3;
|
||||
|
||||
macro_rules! assign {
|
||||
($i:ident) => {
|
||||
$i = 1;
|
||||
};
|
||||
}
|
||||
let x;
|
||||
assign!(x);
|
||||
|
||||
let x;
|
||||
if true {
|
||||
assign!(x);
|
||||
} else {
|
||||
x = 2;
|
||||
}
|
||||
|
||||
macro_rules! in_macro {
|
||||
() => {
|
||||
let x;
|
||||
x = 1;
|
||||
|
||||
let x;
|
||||
if true {
|
||||
x = 1;
|
||||
} else {
|
||||
x = 2;
|
||||
}
|
||||
};
|
||||
}
|
||||
in_macro!();
|
||||
|
||||
println!("{}", x);
|
||||
}
|
108
tests/ui/needless_late_init.stderr
Normal file
108
tests/ui/needless_late_init.stderr
Normal file
|
@ -0,0 +1,108 @@
|
|||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init.rs:4:5
|
||||
|
|
||||
LL | let a;
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: `-D clippy::needless-late-init` implied by `-D warnings`
|
||||
help: declare `a` here
|
||||
|
|
||||
LL | let a = match n {
|
||||
| +++++++
|
||||
help: remove the assignments from the match arms
|
||||
|
|
||||
LL ~ 1 => "one",
|
||||
LL | _ => {
|
||||
LL ~ "two"
|
||||
|
|
||||
help: add a semicolon after the match expression
|
||||
|
|
||||
LL | };
|
||||
| +
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init.rs:13:5
|
||||
|
|
||||
LL | let b;
|
||||
| ^^^^^^
|
||||
|
|
||||
help: declare `b` here
|
||||
|
|
||||
LL | let b = if n == 3 {
|
||||
| +++++++
|
||||
help: remove the assignments from the branches
|
||||
|
|
||||
LL ~ "four"
|
||||
LL | } else {
|
||||
LL ~ "five"
|
||||
|
|
||||
help: add a semicolon after the if expression
|
||||
|
|
||||
LL | };
|
||||
| +
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init.rs:20:5
|
||||
|
|
||||
LL | let c;
|
||||
| ^^^^^^
|
||||
|
|
||||
help: declare `c` here
|
||||
|
|
||||
LL | let c = if let Some(n) = Some(5) {
|
||||
| +++++++
|
||||
help: remove the assignments from the branches
|
||||
|
|
||||
LL ~ n
|
||||
LL | } else {
|
||||
LL ~ -50
|
||||
|
|
||||
help: add a semicolon after the if expression
|
||||
|
|
||||
LL | };
|
||||
| +
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init.rs:27:5
|
||||
|
|
||||
LL | let d;
|
||||
| ^^^^^^
|
||||
|
|
||||
help: declare `d` here
|
||||
|
|
||||
LL | let d = if true {
|
||||
| +++++++
|
||||
help: remove the assignments from the branches
|
||||
|
|
||||
LL ~ temp
|
||||
LL | } else {
|
||||
LL ~ 15
|
||||
|
|
||||
help: add a semicolon after the if expression
|
||||
|
|
||||
LL | };
|
||||
| +
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init.rs:35:5
|
||||
|
|
||||
LL | let e;
|
||||
| ^^^^^^
|
||||
|
|
||||
help: declare `e` here
|
||||
|
|
||||
LL | let e = if true {
|
||||
| +++++++
|
||||
help: remove the assignments from the branches
|
||||
|
|
||||
LL ~ format!("{} {}", a, b)
|
||||
LL | } else {
|
||||
LL ~ format!("{}", c)
|
||||
|
|
||||
help: add a semicolon after the if expression
|
||||
|
|
||||
LL | };
|
||||
| +
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
38
tests/ui/needless_late_init_fixable.fixed
Normal file
38
tests/ui/needless_late_init_fixable.fixed
Normal file
|
@ -0,0 +1,38 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(unused, clippy::assign_op_pattern)]
|
||||
|
||||
fn main() {
|
||||
|
||||
let a = "zero";
|
||||
|
||||
|
||||
|
||||
let b = 1;
|
||||
let c = 2;
|
||||
|
||||
|
||||
let d: usize = 1;
|
||||
|
||||
|
||||
let mut e = 1;
|
||||
e = 2;
|
||||
|
||||
|
||||
let f = match 1 {
|
||||
1 => "three",
|
||||
_ => return,
|
||||
}; // has semi
|
||||
|
||||
|
||||
let g: usize = if true {
|
||||
5
|
||||
} else {
|
||||
panic!();
|
||||
};
|
||||
|
||||
|
||||
let h = format!("{}", e);
|
||||
|
||||
println!("{}", a);
|
||||
}
|
38
tests/ui/needless_late_init_fixable.rs
Normal file
38
tests/ui/needless_late_init_fixable.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(unused, clippy::assign_op_pattern)]
|
||||
|
||||
fn main() {
|
||||
let a;
|
||||
a = "zero";
|
||||
|
||||
let b;
|
||||
let c;
|
||||
b = 1;
|
||||
c = 2;
|
||||
|
||||
let d: usize;
|
||||
d = 1;
|
||||
|
||||
let mut e;
|
||||
e = 1;
|
||||
e = 2;
|
||||
|
||||
let f;
|
||||
match 1 {
|
||||
1 => f = "three",
|
||||
_ => return,
|
||||
}; // has semi
|
||||
|
||||
let g: usize;
|
||||
if true {
|
||||
g = 5;
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
|
||||
let h;
|
||||
h = format!("{}", e);
|
||||
|
||||
println!("{}", a);
|
||||
}
|
103
tests/ui/needless_late_init_fixable.stderr
Normal file
103
tests/ui/needless_late_init_fixable.stderr
Normal file
|
@ -0,0 +1,103 @@
|
|||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:6:5
|
||||
|
|
||||
LL | let a;
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: `-D clippy::needless-late-init` implied by `-D warnings`
|
||||
help: declare `a` here
|
||||
|
|
||||
LL | let a = "zero";
|
||||
| ~~~~~
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:9:5
|
||||
|
|
||||
LL | let b;
|
||||
| ^^^^^^
|
||||
|
|
||||
help: declare `b` here
|
||||
|
|
||||
LL | let b = 1;
|
||||
| ~~~~~
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:10:5
|
||||
|
|
||||
LL | let c;
|
||||
| ^^^^^^
|
||||
|
|
||||
help: declare `c` here
|
||||
|
|
||||
LL | let c = 2;
|
||||
| ~~~~~
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:14:5
|
||||
|
|
||||
LL | let d: usize;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: declare `d` here
|
||||
|
|
||||
LL | let d: usize = 1;
|
||||
| ~~~~~~~~~~~~
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:17:5
|
||||
|
|
||||
LL | let mut e;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
help: declare `e` here
|
||||
|
|
||||
LL | let mut e = 1;
|
||||
| ~~~~~~~~~
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:21:5
|
||||
|
|
||||
LL | let f;
|
||||
| ^^^^^^
|
||||
|
|
||||
help: declare `f` here
|
||||
|
|
||||
LL | let f = match 1 {
|
||||
| +++++++
|
||||
help: remove the assignments from the match arms
|
||||
|
|
||||
LL | 1 => "three",
|
||||
| ~~~~~~~
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:27:5
|
||||
|
|
||||
LL | let g: usize;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: declare `g` here
|
||||
|
|
||||
LL | let g: usize = if true {
|
||||
| ++++++++++++++
|
||||
help: remove the assignments from the branches
|
||||
|
|
||||
LL | 5
|
||||
|
|
||||
help: add a semicolon after the if expression
|
||||
|
|
||||
LL | };
|
||||
| +
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:34:5
|
||||
|
|
||||
LL | let h;
|
||||
| ^^^^^^
|
||||
|
|
||||
help: declare `h` here
|
||||
|
|
||||
LL | let h = format!("{}", e);
|
||||
| ~~~~~
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// non rustfixable, see redundant_closure_call_fixable.rs
|
||||
|
||||
#![warn(clippy::redundant_closure_call)]
|
||||
#![allow(clippy::needless_late_init)]
|
||||
|
||||
fn main() {
|
||||
let mut i = 1;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: closure called just once immediately after it was declared
|
||||
--> $DIR/redundant_closure_call_late.rs:15:5
|
||||
--> $DIR/redundant_closure_call_late.rs:16:5
|
||||
|
|
||||
LL | i = redun_closure();
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -7,13 +7,13 @@ LL | i = redun_closure();
|
|||
= note: `-D clippy::redundant-closure-call` implied by `-D warnings`
|
||||
|
||||
error: closure called just once immediately after it was declared
|
||||
--> $DIR/redundant_closure_call_late.rs:19:5
|
||||
--> $DIR/redundant_closure_call_late.rs:20:5
|
||||
|
|
||||
LL | i = shadowed_closure();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: closure called just once immediately after it was declared
|
||||
--> $DIR/redundant_closure_call_late.rs:21:5
|
||||
--> $DIR/redundant_closure_call_late.rs:22:5
|
||||
|
|
||||
LL | i = shadowed_closure();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![warn(clippy::redundant_else)]
|
||||
#![allow(clippy::needless_return, clippy::if_same_then_else)]
|
||||
#![allow(clippy::needless_return, clippy::if_same_then_else, clippy::needless_late_init)]
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
|
|
Loading…
Reference in a new issue