Auto merge of #5134 - flip1995:snippet_block, r=phansch

Make it possible to correctly indent snippet_block snippets

This adds a `indent_relative_to` arg to the `{snippet,expr}_block` functions. This makes it possible to keep the correct indentation of block like suggestions.

In addition, this makes the `trim_multiline` function private and adds a `indent_of` function, to get the indentation of the first line of a span.

The suggestion of `needless_continue` cannot be made auto applicable, since it would be also necessary to remove code following the linted expression. (Well, maybe it is possible, but I don't know how to do it. Expanding the suggestion span to the last expression, that should be removed didn't work)

changelog: Improve suggestions, when blocks of code are involved
This commit is contained in:
bors 2020-02-06 21:41:50 +00:00
commit b5e6d6db41
22 changed files with 698 additions and 598 deletions

View file

@ -2,7 +2,7 @@
use crate::reexport::*;
use crate::utils::{
is_present_in_source, last_line_of_span, match_def_path, paths, snippet_opt, span_lint, span_lint_and_sugg,
first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_sugg,
span_lint_and_then, without_block_comments,
};
use if_chain::if_chain;
@ -261,7 +261,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Attributes {
_ => {},
}
}
let line_span = last_line_of_span(cx, attr.span);
let line_span = first_line_of_span(cx, attr.span);
if let Some(mut sugg) = snippet_opt(cx, line_span) {
if sugg.contains("#[") {

View file

@ -2,6 +2,7 @@ use crate::utils::*;
use matches::matches;
use rustc::hir::map::Map;
use rustc::lint::in_external_macro;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass, LintContext};
@ -79,8 +80,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
if in_external_macro(cx.sess(), expr.span) {
return;
}
if let Some((check, then, _)) = higher::if_block(&expr) {
if let ExprKind::Block(block, _) = &check.kind {
if let Some((cond, _, _)) = higher::if_block(&expr) {
if let ExprKind::Block(block, _) = &cond.kind {
if block.rules == BlockCheckMode::DefaultBlock {
if block.stmts.is_empty() {
if let Some(ex) = &block.expr {
@ -89,16 +90,24 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
if expr.span.from_expansion() || differing_macro_contexts(expr.span, ex.span) {
return;
}
span_lint_and_help(
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
BLOCK_IN_IF_CONDITION_EXPR,
check.span,
cond.span,
BRACED_EXPR_MESSAGE,
&format!(
"try\nif {} {} ... ",
snippet_block(cx, ex.span, ".."),
snippet_block(cx, then.span, "..")
"try",
format!(
"{}",
snippet_block_with_applicability(
cx,
ex.span,
"..",
Some(expr.span),
&mut applicability
)
),
applicability,
);
}
} else {
@ -107,22 +116,30 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
return;
}
// move block higher
span_lint_and_help(
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
BLOCK_IN_IF_CONDITION_STMT,
check.span,
expr.span.with_hi(cond.span.hi()),
COMPLEX_BLOCK_MESSAGE,
&format!(
"try\nlet res = {};\nif res {} ... ",
snippet_block(cx, block.span, ".."),
snippet_block(cx, then.span, "..")
"try",
format!(
"let res = {}; if res",
snippet_block_with_applicability(
cx,
block.span,
"..",
Some(expr.span),
&mut applicability
),
),
applicability,
);
}
}
} else {
let mut visitor = ExVisitor { found_block: None, cx };
walk_expr(&mut visitor, check);
walk_expr(&mut visitor, cond);
if let Some(block) = visitor.found_block {
span_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE);
}

View file

@ -95,7 +95,7 @@ fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
fn block_starts_with_comment(cx: &EarlyContext<'_>, expr: &ast::Block) -> bool {
// We trim all opening braces and whitespaces and then check if the next string is a comment.
let trimmed_block_text = snippet_block(cx, expr.span, "..")
let trimmed_block_text = snippet_block(cx, expr.span, "..", None)
.trim_start_matches(|c: char| c.is_whitespace() || c == '{')
.to_owned();
trimmed_block_text.starts_with("//") || trimmed_block_text.starts_with("/*")
@ -116,7 +116,7 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) {
block.span,
"this `else { if .. }` block can be collapsed",
"try",
snippet_block_with_applicability(cx, else_.span, "..", &mut applicability).into_owned(),
snippet_block_with_applicability(cx, else_.span, "..", Some(block.span), &mut applicability).into_owned(),
applicability,
);
}
@ -146,7 +146,7 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &
format!(
"if {} {}",
lhs.and(&rhs),
snippet_block(cx, content.span, ".."),
snippet_block(cx, content.span, "..", Some(expr.span)),
),
Applicability::MachineApplicable, // snippet
);

View file

@ -3,9 +3,9 @@ use crate::utils::paths;
use crate::utils::sugg::Sugg;
use crate::utils::usage::is_unused;
use crate::utils::{
expr_block, get_arg_name, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, match_type,
match_var, multispan_sugg, remove_blocks, snippet, snippet_block, snippet_with_applicability, span_lint_and_help,
span_lint_and_note, span_lint_and_sugg, span_lint_and_then, walk_ptrs_ty,
expr_block, get_arg_name, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath,
match_type, match_var, multispan_sugg, remove_blocks, snippet, snippet_block, snippet_with_applicability,
span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, walk_ptrs_ty,
};
use if_chain::if_chain;
use rustc::lint::in_external_macro;
@ -434,7 +434,7 @@ fn report_single_match_single_pattern(
) {
let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
let els_str = els.map_or(String::new(), |els| {
format!(" else {}", expr_block(cx, els, None, ".."))
format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span)))
});
span_lint_and_sugg(
cx,
@ -447,7 +447,7 @@ fn report_single_match_single_pattern(
"if let {} = {} {}{}",
snippet(cx, arms[0].pat.span, ".."),
snippet(cx, ex.span, ".."),
expr_block(cx, &arms[0].body, None, ".."),
expr_block(cx, &arms[0].body, None, "..", Some(expr.span)),
els_str,
),
Applicability::HasPlaceholders,
@ -523,17 +523,21 @@ fn check_match_bool(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>], e
(false, false) => Some(format!(
"if {} {} else {}",
snippet(cx, ex.span, "b"),
expr_block(cx, true_expr, None, ".."),
expr_block(cx, false_expr, None, "..")
expr_block(cx, true_expr, None, "..", Some(expr.span)),
expr_block(cx, false_expr, None, "..", Some(expr.span))
)),
(false, true) => Some(format!(
"if {} {}",
snippet(cx, ex.span, "b"),
expr_block(cx, true_expr, None, "..")
expr_block(cx, true_expr, None, "..", Some(expr.span))
)),
(true, false) => {
let test = Sugg::hir(cx, ex, "..");
Some(format!("if {} {}", !test, expr_block(cx, false_expr, None, "..")))
Some(format!(
"if {} {}",
!test,
expr_block(cx, false_expr, None, "..", Some(expr.span))
))
},
(true, true) => None,
};
@ -832,7 +836,7 @@ fn check_match_single_binding(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[A
let mut snippet_body = if match_body.span.from_expansion() {
Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
} else {
snippet_block(cx, match_body.span, "..").to_owned().to_string()
snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string()
};
// Do we need to add ';' to suggestion ?
@ -861,10 +865,11 @@ fn check_match_single_binding(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[A
"this match could be written as a `let` statement",
"consider using `let` statement",
format!(
"let {} = {};\n{}",
"let {} = {};\n{}{}",
snippet_with_applicability(cx, bind_names, "..", &mut applicability),
snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
snippet_body
" ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
snippet_body,
),
applicability,
);

View file

@ -36,10 +36,10 @@
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::{original_sp, DUMMY_SP};
use std::borrow::Cow;
use rustc_span::Span;
use syntax::ast;
use crate::utils::{snippet, snippet_block, span_lint_and_help, trim_multiline};
use crate::utils::{indent_of, snippet, snippet_block, span_lint_and_help};
declare_clippy_lint! {
/// **What it does:** The lint checks for `if`-statements appearing in loops
@ -119,9 +119,9 @@ declare_clippy_lint! {
declare_lint_pass!(NeedlessContinue => [NEEDLESS_CONTINUE]);
impl EarlyLintPass for NeedlessContinue {
fn check_expr(&mut self, ctx: &EarlyContext<'_>, expr: &ast::Expr) {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
if !expr.span.from_expansion() {
check_and_warn(ctx, expr);
check_and_warn(cx, expr);
}
}
}
@ -273,93 +273,96 @@ struct LintData<'a> {
block_stmts: &'a [ast::Stmt],
}
const MSG_REDUNDANT_ELSE_BLOCK: &str = "This `else` block is redundant.\n";
const MSG_REDUNDANT_ELSE_BLOCK: &str = "this `else` block is redundant";
const MSG_ELSE_BLOCK_NOT_NEEDED: &str = "There is no need for an explicit `else` block for this `if` \
expression\n";
const MSG_ELSE_BLOCK_NOT_NEEDED: &str = "there is no need for an explicit `else` block for this `if` \
expression";
const DROP_ELSE_BLOCK_AND_MERGE_MSG: &str = "Consider dropping the `else` clause and merging the code that \
follows (in the loop) with the `if` block, like so:\n";
const DROP_ELSE_BLOCK_AND_MERGE_MSG: &str = "consider dropping the `else` clause and merging the code that \
follows (in the loop) with the `if` block";
const DROP_ELSE_BLOCK_MSG: &str = "Consider dropping the `else` clause, and moving out the code in the `else` \
block, like so:\n";
const DROP_ELSE_BLOCK_MSG: &str = "consider dropping the `else` clause";
fn emit_warning<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, typ: LintType) {
fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, typ: LintType) {
// snip is the whole *help* message that appears after the warning.
// message is the warning message.
// expr is the expression which the lint warning message refers to.
let (snip, message, expr) = match typ {
LintType::ContinueInsideElseBlock => (
suggestion_snippet_for_continue_inside_else(ctx, data, header),
suggestion_snippet_for_continue_inside_else(cx, data),
MSG_REDUNDANT_ELSE_BLOCK,
data.else_expr,
),
LintType::ContinueInsideThenBlock => (
suggestion_snippet_for_continue_inside_if(ctx, data, header),
suggestion_snippet_for_continue_inside_if(cx, data),
MSG_ELSE_BLOCK_NOT_NEEDED,
data.if_expr,
),
};
span_lint_and_help(ctx, NEEDLESS_CONTINUE, expr.span, message, &snip);
span_lint_and_help(
cx,
NEEDLESS_CONTINUE,
expr.span,
message,
&format!("{}\n{}", header, snip),
);
}
fn suggestion_snippet_for_continue_inside_if<'a>(
ctx: &EarlyContext<'_>,
data: &'a LintData<'_>,
header: &str,
) -> String {
let cond_code = snippet(ctx, data.if_cond.span, "..");
fn suggestion_snippet_for_continue_inside_if<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>) -> String {
let cond_code = snippet(cx, data.if_cond.span, "..");
let if_code = format!("if {} {{\n continue;\n}}\n", cond_code);
/* ^^^^--- Four spaces of indentation. */
// region B
let else_code = snippet(ctx, data.else_expr.span, "..").into_owned();
let else_code = erode_block(&else_code);
let else_code = trim_multiline(Cow::from(else_code), false);
let continue_code = snippet_block(cx, data.if_block.span, "..", Some(data.if_expr.span));
let mut ret = String::from(header);
ret.push_str(&if_code);
ret.push_str(&else_code);
ret.push_str("\n...");
ret
let else_code = snippet_block(cx, data.else_expr.span, "..", Some(data.if_expr.span));
let indent_if = indent_of(cx, data.if_expr.span).unwrap_or(0);
format!(
"{indent}if {} {}\n{indent}{}",
cond_code,
continue_code,
else_code,
indent = " ".repeat(indent_if),
)
}
fn suggestion_snippet_for_continue_inside_else<'a>(
ctx: &EarlyContext<'_>,
data: &'a LintData<'_>,
header: &str,
) -> String {
let cond_code = snippet(ctx, data.if_cond.span, "..");
let mut if_code = format!("if {} {{\n", cond_code);
fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>) -> String {
let cond_code = snippet(cx, data.if_cond.span, "..");
// Region B
let block_code = &snippet(ctx, data.if_block.span, "..").into_owned();
let block_code = erode_block(block_code);
let block_code = trim_multiline(Cow::from(block_code), false);
if_code.push_str(&block_code);
let block_code = erode_from_back(&snippet_block(cx, data.if_block.span, "..", Some(data.if_expr.span)));
// Region C
// These is the code in the loop block that follows the if/else construction
// we are complaining about. We want to pull all of this code into the
// `then` block of the `if` statement.
let indent = span_of_first_expr_in_block(data.if_block)
.and_then(|span| indent_of(cx, span))
.unwrap_or(0);
let to_annex = data.block_stmts[data.stmt_idx + 1..]
.iter()
.map(|stmt| original_sp(stmt.span, DUMMY_SP))
.map(|span| snippet_block(ctx, span, "..").into_owned())
.map(|span| {
let snip = snippet_block(cx, span, "..", None).into_owned();
snip.lines()
.map(|line| format!("{}{}", " ".repeat(indent), line))
.collect::<Vec<_>>()
.join("\n")
})
.collect::<Vec<_>>()
.join("\n");
let mut ret = String::from(header);
ret.push_str(&if_code);
ret.push_str("\n// Merged code follows...");
ret.push_str(&to_annex);
ret.push_str("\n}\n");
ret
let indent_if = indent_of(cx, data.if_expr.span).unwrap_or(0);
format!(
"{indent_if}if {} {}\n{indent}// merged code follows:\n{}\n{indent_if}}}",
cond_code,
block_code,
to_annex,
indent = " ".repeat(indent),
indent_if = " ".repeat(indent_if),
)
}
fn check_and_warn<'a>(ctx: &EarlyContext<'_>, expr: &'a ast::Expr) {
fn check_and_warn<'a>(cx: &EarlyContext<'_>, expr: &'a ast::Expr) {
with_loop_block(expr, |loop_block, label| {
for (i, stmt) in loop_block.stmts.iter().enumerate() {
with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
@ -373,22 +376,22 @@ fn check_and_warn<'a>(ctx: &EarlyContext<'_>, expr: &'a ast::Expr) {
};
if needless_continue_in_else(else_expr, label) {
emit_warning(
ctx,
cx,
data,
DROP_ELSE_BLOCK_AND_MERGE_MSG,
LintType::ContinueInsideElseBlock,
);
} else if is_first_block_stmt_continue(then_block, label) {
emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
emit_warning(cx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
}
});
}
});
}
/// Eats at `s` from the end till a closing brace `}` is encountered, and then
/// continues eating till a non-whitespace character is found.
/// e.g., the string
/// Eats at `s` from the end till a closing brace `}` is encountered, and then continues eating
/// till a non-whitespace character is found. e.g., the string. If no closing `}` is present, the
/// string will be preserved.
///
/// ```rust
/// {
@ -402,12 +405,9 @@ fn check_and_warn<'a>(ctx: &EarlyContext<'_>, expr: &'a ast::Expr) {
/// {
/// let x = 5;
/// ```
///
/// NOTE: when there is no closing brace in `s`, `s` is _not_ preserved, i.e.,
/// an empty string will be returned in that case.
#[must_use]
pub fn erode_from_back(s: &str) -> String {
let mut ret = String::from(s);
fn erode_from_back(s: &str) -> String {
let mut ret = s.to_string();
while ret.pop().map_or(false, |c| c != '}') {}
while let Some(c) = ret.pop() {
if !c.is_whitespace() {
@ -415,41 +415,48 @@ pub fn erode_from_back(s: &str) -> String {
break;
}
}
ret
if ret.is_empty() {
s.to_string()
} else {
ret
}
}
/// Eats at `s` from the front by first skipping all leading whitespace. Then,
/// any number of opening braces are eaten, followed by any number of newlines.
/// e.g., the string
///
/// ```ignore
/// {
/// something();
/// inside_a_block();
/// }
/// ```
///
/// is transformed to
///
/// ```ignore
/// something();
/// inside_a_block();
/// }
/// ```
#[must_use]
pub fn erode_from_front(s: &str) -> String {
s.chars()
.skip_while(|c| c.is_whitespace())
.skip_while(|c| *c == '{')
.skip_while(|c| *c == '\n')
.collect::<String>()
fn span_of_first_expr_in_block(block: &ast::Block) -> Option<Span> {
block.stmts.iter().next().map(|stmt| stmt.span)
}
/// If `s` contains the code for a block, delimited by braces, this function
/// tries to get the contents of the block. If there is no closing brace
/// present,
/// an empty string is returned.
#[must_use]
pub fn erode_block(s: &str) -> String {
erode_from_back(&erode_from_front(s))
#[cfg(test)]
mod test {
use super::erode_from_back;
#[test]
#[rustfmt::skip]
fn test_erode_from_back() {
let input = "\
{
let x = 5;
let y = format!(\"{}\", 42);
}";
let expected = "\
{
let x = 5;
let y = format!(\"{}\", 42);";
let got = erode_from_back(input);
assert_eq!(expected, got);
}
#[test]
#[rustfmt::skip]
fn test_erode_from_back_no_brace() {
let input = "\
let x = 5;
let y = something();
";
let expected = input;
let got = erode_from_back(input);
assert_eq!(expected, got);
}
}

View file

@ -44,6 +44,7 @@ use rustc_hir::Node;
use rustc_hir::*;
use rustc_lint::{LateContext, Level, Lint, LintContext};
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::source_map::original_sp;
use rustc_span::symbol::{self, kw, Symbol};
use rustc_span::{BytePos, Pos, Span, DUMMY_SP};
use smallvec::SmallVec;
@ -533,19 +534,49 @@ pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> {
cx.sess().source_map().span_to_snippet(span).ok()
}
/// Converts a span (from a block) to a code snippet if available, otherwise use
/// default.
/// This trims the code of indentation, except for the first line. Use it for
/// blocks or block-like
/// Converts a span (from a block) to a code snippet if available, otherwise use default.
///
/// This trims the code of indentation, except for the first line. Use it for blocks or block-like
/// things which need to be printed as such.
///
/// The `indent_relative_to` arg can be used, to provide a span, where the indentation of the
/// resulting snippet of the given span.
///
/// # Example
///
/// ```rust,ignore
/// snippet_block(cx, expr.span, "..")
/// snippet_block(cx, block.span, "..", None)
/// // where, `block` is the block of the if expr
/// if x {
/// y;
/// }
/// // will return the snippet
/// {
/// y;
/// }
/// ```
pub fn snippet_block<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
///
/// ```rust,ignore
/// snippet_block(cx, block.span, "..", Some(if_expr.span))
/// // where, `block` is the block of the if expr
/// if x {
/// y;
/// }
/// // will return the snippet
/// {
/// y;
/// } // aligned with `if`
/// ```
/// Note that the first line of the snippet always has 0 indentation.
pub fn snippet_block<'a, T: LintContext>(
cx: &T,
span: Span,
default: &'a str,
indent_relative_to: Option<Span>,
) -> Cow<'a, str> {
let snip = snippet(cx, span, default);
trim_multiline(snip, true)
let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
trim_multiline(snip, true, indent)
}
/// Same as `snippet_block`, but adapts the applicability level by the rules of
@ -554,27 +585,73 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>(
cx: &T,
span: Span,
default: &'a str,
indent_relative_to: Option<Span>,
applicability: &mut Applicability,
) -> Cow<'a, str> {
let snip = snippet_with_applicability(cx, span, default, applicability);
trim_multiline(snip, true)
let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
trim_multiline(snip, true, indent)
}
/// Returns a new Span that covers the full last line of the given Span
pub fn last_line_of_span<T: LintContext>(cx: &T, span: Span) -> Span {
/// Returns a new Span that extends the original Span to the first non-whitespace char of the first
/// line.
///
/// ```rust,ignore
/// let x = ();
/// // ^^
/// // will be converted to
/// let x = ();
/// // ^^^^^^^^^^
/// ```
pub fn first_line_of_span<T: LintContext>(cx: &T, span: Span) -> Span {
if let Some(first_char_pos) = first_char_in_first_line(cx, span) {
span.with_lo(first_char_pos)
} else {
span
}
}
fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePos> {
let line_span = line_span(cx, span);
if let Some(snip) = snippet_opt(cx, line_span) {
snip.find(|c: char| !c.is_whitespace())
.map(|pos| line_span.lo() + BytePos::from_usize(pos))
} else {
None
}
}
/// Returns the indentation of the line of a span
///
/// ```rust,ignore
/// let x = ();
/// // ^^ -- will return 0
/// let x = ();
/// // ^^ -- will return 4
/// ```
pub fn indent_of<T: LintContext>(cx: &T, span: Span) -> Option<usize> {
if let Some(snip) = snippet_opt(cx, line_span(cx, span)) {
snip.find(|c: char| !c.is_whitespace())
} else {
None
}
}
/// Extends the span to the beginning of the spans line, incl. whitespaces.
///
/// ```rust,ignore
/// let x = ();
/// // ^^
/// // will be converted to
/// let x = ();
/// // ^^^^^^^^^^^^^^
/// ```
fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
let span = original_sp(span, DUMMY_SP);
let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap();
let line_no = source_map_and_line.line;
let line_start = &source_map_and_line.sf.lines[line_no];
let span = Span::new(*line_start, span.hi(), span.ctxt());
if_chain! {
if let Some(snip) = snippet_opt(cx, span);
if let Some(first_ch_pos) = snip.find(|c: char| !c.is_whitespace());
then {
span.with_lo(span.lo() + BytePos::from_usize(first_ch_pos))
} else {
span
}
}
let line_start = source_map_and_line.sf.lines[line_no];
Span::new(line_start, span.hi(), span.ctxt())
}
/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
@ -584,8 +661,9 @@ pub fn expr_block<'a, T: LintContext>(
expr: &Expr<'_>,
option: Option<String>,
default: &'a str,
indent_relative_to: Option<Span>,
) -> Cow<'a, str> {
let code = snippet_block(cx, expr.span, default);
let code = snippet_block(cx, expr.span, default, indent_relative_to);
let string = option.unwrap_or_default();
if expr.span.from_expansion() {
Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default)))
@ -600,14 +678,14 @@ pub fn expr_block<'a, T: LintContext>(
/// Trim indentation from a multiline string with possibility of ignoring the
/// first line.
pub fn trim_multiline(s: Cow<'_, str>, ignore_first: bool) -> Cow<'_, str> {
let s_space = trim_multiline_inner(s, ignore_first, ' ');
let s_tab = trim_multiline_inner(s_space, ignore_first, '\t');
trim_multiline_inner(s_tab, ignore_first, ' ')
fn trim_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>) -> Cow<'_, str> {
let s_space = trim_multiline_inner(s, ignore_first, indent, ' ');
let s_tab = trim_multiline_inner(s_space, ignore_first, indent, '\t');
trim_multiline_inner(s_tab, ignore_first, indent, ' ')
}
fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, ch: char) -> Cow<'_, str> {
let x = s
fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>, ch: char) -> Cow<'_, str> {
let mut x = s
.lines()
.skip(ignore_first as usize)
.filter_map(|l| {
@ -620,6 +698,9 @@ fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, ch: char) -> Cow<'_
})
.min()
.unwrap_or(0);
if let Some(indent) = indent {
x = x.saturating_sub(indent);
}
if x > 0 {
Cow::Owned(
s.lines()
@ -1141,87 +1222,6 @@ pub fn is_normalizable<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, param_env: ty::Para
})
}
#[cfg(test)]
mod test {
use super::{trim_multiline, without_block_comments};
#[test]
fn test_trim_multiline_single_line() {
assert_eq!("", trim_multiline("".into(), false));
assert_eq!("...", trim_multiline("...".into(), false));
assert_eq!("...", trim_multiline(" ...".into(), false));
assert_eq!("...", trim_multiline("\t...".into(), false));
assert_eq!("...", trim_multiline("\t\t...".into(), false));
}
#[test]
#[rustfmt::skip]
fn test_trim_multiline_block() {
assert_eq!("\
if x {
y
} else {
z
}", trim_multiline(" if x {
y
} else {
z
}".into(), false));
assert_eq!("\
if x {
\ty
} else {
\tz
}", trim_multiline(" if x {
\ty
} else {
\tz
}".into(), false));
}
#[test]
#[rustfmt::skip]
fn test_trim_multiline_empty_line() {
assert_eq!("\
if x {
y
} else {
z
}", trim_multiline(" if x {
y
} else {
z
}".into(), false));
}
#[test]
fn test_without_block_comments_lines_without_block_comments() {
let result = without_block_comments(vec!["/*", "", "*/"]);
println!("result: {:?}", result);
assert!(result.is_empty());
let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]);
assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]);
let result = without_block_comments(vec!["/* rust", "", "*/"]);
assert!(result.is_empty());
let result = without_block_comments(vec!["/* one-line comment */"]);
assert!(result.is_empty());
let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]);
assert!(result.is_empty());
let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]);
assert!(result.is_empty());
let result = without_block_comments(vec!["foo", "bar", "baz"]);
assert_eq!(result, vec!["foo", "bar", "baz"]);
}
}
pub fn match_def_path<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, did: DefId, syms: &[&str]) -> bool {
let path = cx.get_def_path(did);
path.len() == syms.len() && path.into_iter().zip(syms.iter()).all(|(a, &b)| a.as_str() == b)
@ -1369,3 +1369,84 @@ pub fn is_trait_impl_item(cx: &LateContext<'_, '_>, hir_id: HirId) -> bool {
false
}
}
#[cfg(test)]
mod test {
use super::{trim_multiline, without_block_comments};
#[test]
fn test_trim_multiline_single_line() {
assert_eq!("", trim_multiline("".into(), false, None));
assert_eq!("...", trim_multiline("...".into(), false, None));
assert_eq!("...", trim_multiline(" ...".into(), false, None));
assert_eq!("...", trim_multiline("\t...".into(), false, None));
assert_eq!("...", trim_multiline("\t\t...".into(), false, None));
}
#[test]
#[rustfmt::skip]
fn test_trim_multiline_block() {
assert_eq!("\
if x {
y
} else {
z
}", trim_multiline(" if x {
y
} else {
z
}".into(), false, None));
assert_eq!("\
if x {
\ty
} else {
\tz
}", trim_multiline(" if x {
\ty
} else {
\tz
}".into(), false, None));
}
#[test]
#[rustfmt::skip]
fn test_trim_multiline_empty_line() {
assert_eq!("\
if x {
y
} else {
z
}", trim_multiline(" if x {
y
} else {
z
}".into(), false, None));
}
#[test]
fn test_without_block_comments_lines_without_block_comments() {
let result = without_block_comments(vec!["/*", "", "*/"]);
println!("result: {:?}", result);
assert!(result.is_empty());
let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]);
assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]);
let result = without_block_comments(vec!["/* rust", "", "*/"]);
assert!(result.is_empty());
let result = without_block_comments(vec!["/* one-line comment */"]);
assert!(result.is_empty());
let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]);
assert!(result.is_empty());
let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]);
assert!(result.is_empty());
let result = without_block_comments(vec!["foo", "bar", "baz"]);
assert_eq!(result, vec!["foo", "bar", "baz"]);
}
}

View file

@ -1,87 +0,0 @@
// Tests for the various helper functions used by the needless_continue
// lint that don't belong in utils.
use clippy_lints::needless_continue::{erode_block, erode_from_back, erode_from_front};
#[test]
#[rustfmt::skip]
fn test_erode_from_back() {
let input = "\
{
let x = 5;
let y = format!(\"{}\", 42);
}";
let expected = "\
{
let x = 5;
let y = format!(\"{}\", 42);";
let got = erode_from_back(input);
assert_eq!(expected, got);
}
#[test]
#[rustfmt::skip]
fn test_erode_from_back_no_brace() {
let input = "\
let x = 5;
let y = something();
";
let expected = "";
let got = erode_from_back(input);
assert_eq!(expected, got);
}
#[test]
#[rustfmt::skip]
fn test_erode_from_front() {
let input = "
{
something();
inside_a_block();
}
";
let expected =
" something();
inside_a_block();
}
";
let got = erode_from_front(input);
println!("input: {}\nexpected:\n{}\ngot:\n{}", input, expected, got);
assert_eq!(expected, got);
}
#[test]
#[rustfmt::skip]
fn test_erode_from_front_no_brace() {
let input = "
something();
inside_a_block();
";
let expected =
"something();
inside_a_block();
";
let got = erode_from_front(input);
println!("input: {}\nexpected:\n{}\ngot:\n{}", input, expected, got);
assert_eq!(expected, got);
}
#[test]
#[rustfmt::skip]
fn test_erode_block() {
let input = "
{
something();
inside_a_block();
}
";
let expected =
" something();
inside_a_block();";
let got = erode_block(input);
println!("input: {}\nexpected:\n{}\ngot:\n{}", input, expected, got);
assert_eq!(expected, got);
}

View file

@ -0,0 +1,75 @@
// run-rustfix
#![warn(clippy::block_in_if_condition_expr)]
#![warn(clippy::block_in_if_condition_stmt)]
#![allow(unused, clippy::let_and_return)]
#![warn(clippy::nonminimal_bool)]
macro_rules! blocky {
() => {{
true
}};
}
macro_rules! blocky_too {
() => {{
let r = true;
r
}};
}
fn macro_if() {
if blocky!() {}
if blocky_too!() {}
}
fn condition_has_block() -> i32 {
let res = {
let x = 3;
x == 3
}; if res {
6
} else {
10
}
}
fn condition_has_block_with_single_expression() -> i32 {
if true {
6
} else {
10
}
}
fn condition_is_normal() -> i32 {
let x = 3;
if x == 3 {
6
} else {
10
}
}
fn condition_is_unsafe_block() {
let a: i32 = 1;
// this should not warn because the condition is an unsafe block
if unsafe { 1u32 == std::mem::transmute(a) } {
println!("1u32 == a");
}
}
fn block_in_assert() {
let opt = Some(42);
assert!(opt
.as_ref()
.and_then(|val| {
let mut v = val * 2;
v -= 1;
Some(v * 3)
})
.is_some());
}
fn main() {}

View file

@ -1,3 +1,4 @@
// run-rustfix
#![warn(clippy::block_in_if_condition_expr)]
#![warn(clippy::block_in_if_condition_stmt)]
#![allow(unused, clippy::let_and_return)]
@ -41,37 +42,6 @@ fn condition_has_block_with_single_expression() -> i32 {
}
}
fn predicate<F: FnOnce(T) -> bool, T>(pfn: F, val: T) -> bool {
pfn(val)
}
fn pred_test() {
let v = 3;
let sky = "blue";
// This is a sneaky case, where the block isn't directly in the condition,
// but is actually nside a closure that the condition is using.
// The same principle applies -- add some extra expressions to make sure
// linter isn't confused by them.
if v == 3
&& sky == "blue"
&& predicate(
|x| {
let target = 3;
x == target
},
v,
)
{}
if predicate(
|x| {
let target = 3;
x == target
},
v,
) {}
}
fn condition_is_normal() -> i32 {
let x = 3;
if true && x == 3 {
@ -81,10 +51,6 @@ fn condition_is_normal() -> i32 {
}
}
fn closure_without_block() {
if predicate(|x| x == 3, 6) {}
}
fn condition_is_unsafe_block() {
let a: i32 = 1;
@ -94,16 +60,6 @@ fn condition_is_unsafe_block() {
}
}
fn main() {}
fn macro_in_closure() {
let option = Some(true);
if option.unwrap_or_else(|| unimplemented!()) {
unimplemented!()
}
}
fn block_in_assert() {
let opt = Some(42);
assert!(opt
@ -115,3 +71,5 @@ fn block_in_assert() {
})
.is_some());
}
fn main() {}

View file

@ -1,62 +1,36 @@
error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
--> $DIR/block_in_if_condition.rs:26:8
--> $DIR/block_in_if_condition.rs:27:5
|
LL | if {
| ________^
LL | / if {
LL | | let x = 3;
LL | | x == 3
LL | | } {
| |_____^
|
= note: `-D clippy::block-in-if-condition-stmt` implied by `-D warnings`
= help: try
let res = {
let x = 3;
x == 3
};
if res {
6
} ...
help: try
|
LL | let res = {
LL | let x = 3;
LL | x == 3
LL | }; if res {
|
error: omit braces around single expression condition
--> $DIR/block_in_if_condition.rs:37:8
--> $DIR/block_in_if_condition.rs:38:8
|
LL | if { true } {
| ^^^^^^^^
| ^^^^^^^^ help: try: `true`
|
= note: `-D clippy::block-in-if-condition-expr` implied by `-D warnings`
= help: try
if true {
6
} ...
error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
--> $DIR/block_in_if_condition.rs:58:17
|
LL | |x| {
| _________________^
LL | | let target = 3;
LL | | x == target
LL | | },
| |_____________^
error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
--> $DIR/block_in_if_condition.rs:67:13
|
LL | |x| {
| _____________^
LL | | let target = 3;
LL | | x == target
LL | | },
| |_________^
error: this boolean expression can be simplified
--> $DIR/block_in_if_condition.rs:77:8
--> $DIR/block_in_if_condition.rs:47:8
|
LL | if true && x == 3 {
| ^^^^^^^^^^^^^^ help: try: `x == 3`
|
= note: `-D clippy::nonminimal-bool` implied by `-D warnings`
error: aborting due to 5 previous errors
error: aborting due to 3 previous errors

View file

@ -0,0 +1,48 @@
#![warn(clippy::block_in_if_condition_expr)]
#![warn(clippy::block_in_if_condition_stmt)]
#![allow(unused, clippy::let_and_return)]
fn predicate<F: FnOnce(T) -> bool, T>(pfn: F, val: T) -> bool {
pfn(val)
}
fn pred_test() {
let v = 3;
let sky = "blue";
// This is a sneaky case, where the block isn't directly in the condition,
// but is actually nside a closure that the condition is using.
// The same principle applies -- add some extra expressions to make sure
// linter isn't confused by them.
if v == 3
&& sky == "blue"
&& predicate(
|x| {
let target = 3;
x == target
},
v,
)
{}
if predicate(
|x| {
let target = 3;
x == target
},
v,
) {}
}
fn closure_without_block() {
if predicate(|x| x == 3, 6) {}
}
fn macro_in_closure() {
let option = Some(true);
if option.unwrap_or_else(|| unimplemented!()) {
unimplemented!()
}
}
fn main() {}

View file

@ -0,0 +1,24 @@
error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
--> $DIR/block_in_if_condition_closure.rs:19:17
|
LL | |x| {
| _________________^
LL | | let target = 3;
LL | | x == target
LL | | },
| |_____________^
|
= note: `-D clippy::block-in-if-condition-stmt` implied by `-D warnings`
error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
--> $DIR/block_in_if_condition_closure.rs:28:13
|
LL | |x| {
| _____________^
LL | | let target = 3;
LL | | x == target
LL | | },
| |_________^
error: aborting due to 2 previous errors

View file

@ -10,57 +10,57 @@ fn main() {
if x == "hello" {
print!("Hello ");
} else if y == "world" {
println!("world!")
}
println!("world!")
}
if x == "hello" {
print!("Hello ");
} else if let Some(42) = Some(42) {
println!("world!")
}
println!("world!")
}
if x == "hello" {
print!("Hello ");
} else if y == "world" {
println!("world")
}
else {
println!("!")
}
println!("world")
}
else {
println!("!")
}
if x == "hello" {
print!("Hello ");
} else if let Some(42) = Some(42) {
println!("world")
}
else {
println!("!")
}
println!("world")
}
else {
println!("!")
}
if let Some(42) = Some(42) {
print!("Hello ");
} else if let Some(42) = Some(42) {
println!("world")
}
else {
println!("!")
}
println!("world")
}
else {
println!("!")
}
if let Some(42) = Some(42) {
print!("Hello ");
} else if x == "hello" {
println!("world")
}
else {
println!("!")
}
println!("world")
}
else {
println!("!")
}
if let Some(42) = Some(42) {
print!("Hello ");
} else if let Some(42) = Some(42) {
println!("world")
}
else {
println!("!")
}
println!("world")
}
else {
println!("!")
}
}

View file

@ -13,8 +13,8 @@ LL | | }
help: try
|
LL | } else if y == "world" {
LL | println!("world!")
LL | }
LL | println!("world!")
LL | }
|
error: this `else { if .. }` block can be collapsed
@ -31,8 +31,8 @@ LL | | }
help: try
|
LL | } else if let Some(42) = Some(42) {
LL | println!("world!")
LL | }
LL | println!("world!")
LL | }
|
error: this `else { if .. }` block can be collapsed
@ -51,11 +51,11 @@ LL | | }
help: try
|
LL | } else if y == "world" {
LL | println!("world")
LL | }
LL | else {
LL | println!("!")
LL | }
LL | println!("world")
LL | }
LL | else {
LL | println!("!")
LL | }
|
error: this `else { if .. }` block can be collapsed
@ -74,11 +74,11 @@ LL | | }
help: try
|
LL | } else if let Some(42) = Some(42) {
LL | println!("world")
LL | }
LL | else {
LL | println!("!")
LL | }
LL | println!("world")
LL | }
LL | else {
LL | println!("!")
LL | }
|
error: this `else { if .. }` block can be collapsed
@ -97,11 +97,11 @@ LL | | }
help: try
|
LL | } else if let Some(42) = Some(42) {
LL | println!("world")
LL | }
LL | else {
LL | println!("!")
LL | }
LL | println!("world")
LL | }
LL | else {
LL | println!("!")
LL | }
|
error: this `else { if .. }` block can be collapsed
@ -120,11 +120,11 @@ LL | | }
help: try
|
LL | } else if x == "hello" {
LL | println!("world")
LL | }
LL | else {
LL | println!("!")
LL | }
LL | println!("world")
LL | }
LL | else {
LL | println!("!")
LL | }
|
error: this `else { if .. }` block can be collapsed
@ -143,11 +143,11 @@ LL | | }
help: try
|
LL | } else if let Some(42) = Some(42) {
LL | println!("world")
LL | }
LL | else {
LL | println!("!")
LL | }
LL | println!("world")
LL | }
LL | else {
LL | println!("!")
LL | }
|
error: aborting due to 7 previous errors

View file

@ -7,28 +7,28 @@ fn main() {
let x = "hello";
let y = "world";
if x == "hello" && y == "world" {
println!("Hello world!");
}
println!("Hello world!");
}
if (x == "hello" || x == "world") && (y == "world" || y == "hello") {
println!("Hello world!");
}
println!("Hello world!");
}
if x == "hello" && x == "world" && (y == "world" || y == "hello") {
println!("Hello world!");
}
println!("Hello world!");
}
if (x == "hello" || x == "world") && y == "world" && y == "hello" {
println!("Hello world!");
}
println!("Hello world!");
}
if x == "hello" && x == "world" && y == "world" && y == "hello" {
println!("Hello world!");
}
println!("Hello world!");
}
if 42 == 1337 && 'a' != 'A' {
println!("world!")
}
println!("world!")
}
// Works because any if with an else statement cannot be collapsed.
if x == "hello" {
@ -81,8 +81,8 @@ fn main() {
}
if x == "hello" && y == "world" { // Collapsible
println!("Hello world!");
}
println!("Hello world!");
}
if x == "hello" {
print!("Hello ");

View file

@ -12,8 +12,8 @@ LL | | }
help: try
|
LL | if x == "hello" && y == "world" {
LL | println!("Hello world!");
LL | }
LL | println!("Hello world!");
LL | }
|
error: this `if` statement can be collapsed
@ -29,8 +29,8 @@ LL | | }
help: try
|
LL | if (x == "hello" || x == "world") && (y == "world" || y == "hello") {
LL | println!("Hello world!");
LL | }
LL | println!("Hello world!");
LL | }
|
error: this `if` statement can be collapsed
@ -46,8 +46,8 @@ LL | | }
help: try
|
LL | if x == "hello" && x == "world" && (y == "world" || y == "hello") {
LL | println!("Hello world!");
LL | }
LL | println!("Hello world!");
LL | }
|
error: this `if` statement can be collapsed
@ -63,8 +63,8 @@ LL | | }
help: try
|
LL | if (x == "hello" || x == "world") && y == "world" && y == "hello" {
LL | println!("Hello world!");
LL | }
LL | println!("Hello world!");
LL | }
|
error: this `if` statement can be collapsed
@ -80,8 +80,8 @@ LL | | }
help: try
|
LL | if x == "hello" && x == "world" && y == "world" && y == "hello" {
LL | println!("Hello world!");
LL | }
LL | println!("Hello world!");
LL | }
|
error: this `if` statement can be collapsed
@ -97,8 +97,8 @@ LL | | }
help: try
|
LL | if 42 == 1337 && 'a' != 'A' {
LL | println!("world!")
LL | }
LL | println!("world!")
LL | }
|
error: this `if` statement can be collapsed
@ -114,8 +114,8 @@ LL | | }
help: try
|
LL | if x == "hello" && y == "world" { // Collapsible
LL | println!("Hello world!");
LL | }
LL | println!("Hello world!");
LL | }
|
error: aborting due to 7 previous errors

View file

@ -40,8 +40,8 @@ LL | | };
help: consider using an `if`/`else` expression
|
LL | if !test {
LL | println!("Noooo!");
LL | };
LL | println!("Noooo!");
LL | };
|
error: you seem to be trying to match on a boolean expression
@ -58,8 +58,8 @@ LL | | };
help: consider using an `if`/`else` expression
|
LL | if !test {
LL | println!("Noooo!");
LL | };
LL | println!("Noooo!");
LL | };
|
error: you seem to be trying to match on a boolean expression
@ -76,8 +76,8 @@ LL | | };
help: consider using an `if`/`else` expression
|
LL | if !(test && test) {
LL | println!("Noooo!");
LL | };
LL | println!("Noooo!");
LL | };
|
error: equal expressions as operands to `&&`
@ -103,10 +103,10 @@ LL | | };
help: consider using an `if`/`else` expression
|
LL | if test {
LL | println!("Yes!");
LL | } else {
LL | println!("Noooo!");
LL | };
LL | println!("Yes!");
LL | } else {
LL | println!("Noooo!");
LL | };
|
error: aborting due to 8 previous errors

View file

@ -14,12 +14,12 @@ fn main() {
let c = 3;
// Lint
let (x, y, z) = (a, b, c);
{
println!("{} {} {}", x, y, z);
}
{
println!("{} {} {}", x, y, z);
}
// Lint
let (x, y, z) = (a, b, c);
println!("{} {} {}", x, y, z);
println!("{} {} {}", x, y, z);
// Ok
match a {
2 => println!("2"),
@ -35,29 +35,29 @@ println!("{} {} {}", x, y, z);
println!("whatever");
// Lint
{
let x = 29;
println!("x has a value of {}", x);
}
let x = 29;
println!("x has a value of {}", x);
}
// Lint
{
let e = 5 * a;
if e >= 5 {
println!("e is superior to 5");
let e = 5 * a;
if e >= 5 {
println!("e is superior to 5");
}
}
}
// Lint
let p = Point { x: 0, y: 7 };
let Point { x, y } = p;
println!("Coords: ({}, {})", x, y);
println!("Coords: ({}, {})", x, y);
// Lint
let Point { x: x1, y: y1 } = p;
println!("Coords: ({}, {})", x1, y1);
println!("Coords: ({}, {})", x1, y1);
// Lint
let x = 5;
let ref r = x;
println!("Got a reference to {}", r);
println!("Got a reference to {}", r);
// Lint
let mut x = 5;
let ref mut mr = x;
println!("Got a mutable reference to {}", mr);
println!("Got a mutable reference to {}", mr);
}

View file

@ -12,9 +12,9 @@ LL | | }
help: consider using `let` statement
|
LL | let (x, y, z) = (a, b, c);
LL | {
LL | println!("{} {} {}", x, y, z);
LL | }
LL | {
LL | println!("{} {} {}", x, y, z);
LL | }
|
error: this match could be written as a `let` statement
@ -28,7 +28,7 @@ LL | | }
help: consider using `let` statement
|
LL | let (x, y, z) = (a, b, c);
LL | println!("{} {} {}", x, y, z);
LL | println!("{} {} {}", x, y, z);
|
error: this match could be replaced by its body itself
@ -53,9 +53,9 @@ LL | | }
help: consider using the match body instead
|
LL | {
LL | let x = 29;
LL | println!("x has a value of {}", x);
LL | }
LL | let x = 29;
LL | println!("x has a value of {}", x);
LL | }
|
error: this match could be replaced by its body itself
@ -73,11 +73,11 @@ LL | | }
help: consider using the match body instead
|
LL | {
LL | let e = 5 * a;
LL | if e >= 5 {
LL | println!("e is superior to 5");
LL | let e = 5 * a;
LL | if e >= 5 {
LL | println!("e is superior to 5");
LL | }
LL | }
LL | }
|
error: this match could be written as a `let` statement
@ -91,7 +91,7 @@ LL | | }
help: consider using `let` statement
|
LL | let Point { x, y } = p;
LL | println!("Coords: ({}, {})", x, y);
LL | println!("Coords: ({}, {})", x, y);
|
error: this match could be written as a `let` statement
@ -105,7 +105,7 @@ LL | | }
help: consider using `let` statement
|
LL | let Point { x: x1, y: y1 } = p;
LL | println!("Coords: ({}, {})", x1, y1);
LL | println!("Coords: ({}, {})", x1, y1);
|
error: this match could be written as a `let` statement
@ -119,7 +119,7 @@ LL | | }
help: consider using `let` statement
|
LL | let ref r = x;
LL | println!("Got a reference to {}", r);
LL | println!("Got a reference to {}", r);
|
error: this match could be written as a `let` statement
@ -133,7 +133,7 @@ LL | | }
help: consider using `let` statement
|
LL | let ref mut mr = x;
LL | println!("Got a mutable reference to {}", mr);
LL | println!("Got a mutable reference to {}", mr);
|
error: aborting due to 9 previous errors

View file

@ -1,5 +1,4 @@
error: This `else` block is redundant.
error: this `else` block is redundant
--> $DIR/needless_continue.rs:28:16
|
LL | } else {
@ -9,34 +8,33 @@ LL | | }
| |_________^
|
= note: `-D clippy::needless-continue` implied by `-D warnings`
= help: Consider dropping the `else` clause and merging the code that follows (in the loop) with the `if` block, like so:
if i % 2 == 0 && i % 3 == 0 {
println!("{}", i);
println!("{}", i + 1);
if i % 5 == 0 {
println!("{}", i + 2);
}
let i = 0;
println!("bar {} ", i);
// Merged code follows...println!("bleh");
{
println!("blah");
}
if !(!(i == 2) || !(i == 5)) {
println!("lama");
}
if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
continue;
} else {
println!("Blabber");
println!("Jabber");
}
println!("bleh");
}
error: There is no need for an explicit `else` block for this `if` expression
= help: consider dropping the `else` clause and merging the code that follows (in the loop) with the `if` block
if i % 2 == 0 && i % 3 == 0 {
println!("{}", i);
println!("{}", i + 1);
if i % 5 == 0 {
println!("{}", i + 2);
}
let i = 0;
println!("bar {} ", i);
// merged code follows:
println!("bleh");
{
println!("blah");
}
if !(!(i == 2) || !(i == 5)) {
println!("lama");
}
if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
continue;
} else {
println!("Blabber");
println!("Jabber");
}
println!("bleh");
}
error: there is no need for an explicit `else` block for this `if` expression
--> $DIR/needless_continue.rs:43:9
|
LL | / if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
@ -47,16 +45,16 @@ LL | | println!("Jabber");
LL | | }
| |_________^
|
= help: Consider dropping the `else` clause, and moving out the code in the `else` block, like so:
if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
continue;
}
println!("Blabber");
println!("Jabber");
...
error: This `else` block is redundant.
= help: consider dropping the `else` clause
if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
continue;
}
{
println!("Blabber");
println!("Jabber");
}
error: this `else` block is redundant
--> $DIR/needless_continue.rs:100:24
|
LL | } else {
@ -65,22 +63,21 @@ LL | | continue 'inner; // should lint here
LL | | }
| |_________________^
|
= help: Consider dropping the `else` clause and merging the code that follows (in the loop) with the `if` block, like so:
if condition() {
println!("bar-3");
// Merged code follows...println!("bar-4");
update_condition();
if condition() {
continue; // should lint here
} else {
println!("bar-5");
}
println!("bar-6");
}
error: There is no need for an explicit `else` block for this `if` expression
= help: consider dropping the `else` clause and merging the code that follows (in the loop) with the `if` block
if condition() {
println!("bar-3");
// merged code follows:
println!("bar-4");
update_condition();
if condition() {
continue; // should lint here
} else {
println!("bar-5");
}
println!("bar-6");
}
error: there is no need for an explicit `else` block for this `if` expression
--> $DIR/needless_continue.rs:106:17
|
LL | / if condition() {
@ -90,12 +87,13 @@ LL | | println!("bar-5");
LL | | }
| |_________________^
|
= help: Consider dropping the `else` clause, and moving out the code in the `else` block, like so:
if condition() {
continue;
}
println!("bar-5");
...
= help: consider dropping the `else` clause
if condition() {
continue; // should lint here
}
{
println!("bar-5");
}
error: aborting due to 4 previous errors

View file

@ -13,8 +13,8 @@ LL | | };
help: try this
|
LL | if let Some(y) = x {
LL | println!("{:?}", y);
LL | };
LL | println!("{:?}", y);
LL | };
|
error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`

View file

@ -14,9 +14,9 @@ LL | | }
help: try this
|
LL | if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else {
LL | let x = 5;
LL | None
LL | }
LL | let x = 5;
LL | None
LL | }
|
error: aborting due to previous error