Skip to content

Commit b5e6d6d

Browse files
committed
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
2 parents ee842df + e23881e commit b5e6d6d

22 files changed

+700
-600
lines changed

clippy_lints/src/attrs.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use crate::reexport::*;
44
use crate::utils::{
5-
is_present_in_source, last_line_of_span, match_def_path, paths, snippet_opt, span_lint, span_lint_and_sugg,
5+
first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_sugg,
66
span_lint_and_then, without_block_comments,
77
};
88
use if_chain::if_chain;
@@ -261,7 +261,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Attributes {
261261
_ => {},
262262
}
263263
}
264-
let line_span = last_line_of_span(cx, attr.span);
264+
let line_span = first_line_of_span(cx, attr.span);
265265

266266
if let Some(mut sugg) = snippet_opt(cx, line_span) {
267267
if sugg.contains("#[") {

clippy_lints/src/block_in_if_condition.rs

+32-15
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::utils::*;
22
use matches::matches;
33
use rustc::hir::map::Map;
44
use rustc::lint::in_external_macro;
5+
use rustc_errors::Applicability;
56
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
67
use rustc_hir::*;
78
use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -79,8 +80,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
7980
if in_external_macro(cx.sess(), expr.span) {
8081
return;
8182
}
82-
if let Some((check, then, _)) = higher::if_block(&expr) {
83-
if let ExprKind::Block(block, _) = &check.kind {
83+
if let Some((cond, _, _)) = higher::if_block(&expr) {
84+
if let ExprKind::Block(block, _) = &cond.kind {
8485
if block.rules == BlockCheckMode::DefaultBlock {
8586
if block.stmts.is_empty() {
8687
if let Some(ex) = &block.expr {
@@ -89,16 +90,24 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
8990
if expr.span.from_expansion() || differing_macro_contexts(expr.span, ex.span) {
9091
return;
9192
}
92-
span_lint_and_help(
93+
let mut applicability = Applicability::MachineApplicable;
94+
span_lint_and_sugg(
9395
cx,
9496
BLOCK_IN_IF_CONDITION_EXPR,
95-
check.span,
97+
cond.span,
9698
BRACED_EXPR_MESSAGE,
97-
&format!(
98-
"try\nif {} {} ... ",
99-
snippet_block(cx, ex.span, ".."),
100-
snippet_block(cx, then.span, "..")
99+
"try",
100+
format!(
101+
"{}",
102+
snippet_block_with_applicability(
103+
cx,
104+
ex.span,
105+
"..",
106+
Some(expr.span),
107+
&mut applicability
108+
)
101109
),
110+
applicability,
102111
);
103112
}
104113
} else {
@@ -107,22 +116,30 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
107116
return;
108117
}
109118
// move block higher
110-
span_lint_and_help(
119+
let mut applicability = Applicability::MachineApplicable;
120+
span_lint_and_sugg(
111121
cx,
112122
BLOCK_IN_IF_CONDITION_STMT,
113-
check.span,
123+
expr.span.with_hi(cond.span.hi()),
114124
COMPLEX_BLOCK_MESSAGE,
115-
&format!(
116-
"try\nlet res = {};\nif res {} ... ",
117-
snippet_block(cx, block.span, ".."),
118-
snippet_block(cx, then.span, "..")
125+
"try",
126+
format!(
127+
"let res = {}; if res",
128+
snippet_block_with_applicability(
129+
cx,
130+
block.span,
131+
"..",
132+
Some(expr.span),
133+
&mut applicability
134+
),
119135
),
136+
applicability,
120137
);
121138
}
122139
}
123140
} else {
124141
let mut visitor = ExVisitor { found_block: None, cx };
125-
walk_expr(&mut visitor, check);
142+
walk_expr(&mut visitor, cond);
126143
if let Some(block) = visitor.found_block {
127144
span_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE);
128145
}

clippy_lints/src/collapsible_if.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
9595

9696
fn block_starts_with_comment(cx: &EarlyContext<'_>, expr: &ast::Block) -> bool {
9797
// We trim all opening braces and whitespaces and then check if the next string is a comment.
98-
let trimmed_block_text = snippet_block(cx, expr.span, "..")
98+
let trimmed_block_text = snippet_block(cx, expr.span, "..", None)
9999
.trim_start_matches(|c: char| c.is_whitespace() || c == '{')
100100
.to_owned();
101101
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) {
116116
block.span,
117117
"this `else { if .. }` block can be collapsed",
118118
"try",
119-
snippet_block_with_applicability(cx, else_.span, "..", &mut applicability).into_owned(),
119+
snippet_block_with_applicability(cx, else_.span, "..", Some(block.span), &mut applicability).into_owned(),
120120
applicability,
121121
);
122122
}
@@ -146,7 +146,7 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &
146146
format!(
147147
"if {} {}",
148148
lhs.and(&rhs),
149-
snippet_block(cx, content.span, ".."),
149+
snippet_block(cx, content.span, "..", Some(expr.span)),
150150
),
151151
Applicability::MachineApplicable, // snippet
152152
);

clippy_lints/src/matches.rs

+17-12
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ use crate::utils::paths;
33
use crate::utils::sugg::Sugg;
44
use crate::utils::usage::is_unused;
55
use crate::utils::{
6-
expr_block, get_arg_name, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, match_type,
7-
match_var, multispan_sugg, remove_blocks, snippet, snippet_block, snippet_with_applicability, span_lint_and_help,
8-
span_lint_and_note, span_lint_and_sugg, span_lint_and_then, walk_ptrs_ty,
6+
expr_block, get_arg_name, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath,
7+
match_type, match_var, multispan_sugg, remove_blocks, snippet, snippet_block, snippet_with_applicability,
8+
span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, walk_ptrs_ty,
99
};
1010
use if_chain::if_chain;
1111
use rustc::lint::in_external_macro;
@@ -434,7 +434,7 @@ fn report_single_match_single_pattern(
434434
) {
435435
let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
436436
let els_str = els.map_or(String::new(), |els| {
437-
format!(" else {}", expr_block(cx, els, None, ".."))
437+
format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span)))
438438
});
439439
span_lint_and_sugg(
440440
cx,
@@ -447,7 +447,7 @@ fn report_single_match_single_pattern(
447447
"if let {} = {} {}{}",
448448
snippet(cx, arms[0].pat.span, ".."),
449449
snippet(cx, ex.span, ".."),
450-
expr_block(cx, &arms[0].body, None, ".."),
450+
expr_block(cx, &arms[0].body, None, "..", Some(expr.span)),
451451
els_str,
452452
),
453453
Applicability::HasPlaceholders,
@@ -523,17 +523,21 @@ fn check_match_bool(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>], e
523523
(false, false) => Some(format!(
524524
"if {} {} else {}",
525525
snippet(cx, ex.span, "b"),
526-
expr_block(cx, true_expr, None, ".."),
527-
expr_block(cx, false_expr, None, "..")
526+
expr_block(cx, true_expr, None, "..", Some(expr.span)),
527+
expr_block(cx, false_expr, None, "..", Some(expr.span))
528528
)),
529529
(false, true) => Some(format!(
530530
"if {} {}",
531531
snippet(cx, ex.span, "b"),
532-
expr_block(cx, true_expr, None, "..")
532+
expr_block(cx, true_expr, None, "..", Some(expr.span))
533533
)),
534534
(true, false) => {
535535
let test = Sugg::hir(cx, ex, "..");
536-
Some(format!("if {} {}", !test, expr_block(cx, false_expr, None, "..")))
536+
Some(format!(
537+
"if {} {}",
538+
!test,
539+
expr_block(cx, false_expr, None, "..", Some(expr.span))
540+
))
537541
},
538542
(true, true) => None,
539543
};
@@ -832,7 +836,7 @@ fn check_match_single_binding(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[A
832836
let mut snippet_body = if match_body.span.from_expansion() {
833837
Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
834838
} else {
835-
snippet_block(cx, match_body.span, "..").to_owned().to_string()
839+
snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string()
836840
};
837841

838842
// Do we need to add ';' to suggestion ?
@@ -861,10 +865,11 @@ fn check_match_single_binding(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[A
861865
"this match could be written as a `let` statement",
862866
"consider using `let` statement",
863867
format!(
864-
"let {} = {};\n{}",
868+
"let {} = {};\n{}{}",
865869
snippet_with_applicability(cx, bind_names, "..", &mut applicability),
866870
snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
867-
snippet_body
871+
" ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
872+
snippet_body,
868873
),
869874
applicability,
870875
);

0 commit comments

Comments
 (0)