Skip to content

Commit 5da6174

Browse files
committed
Auto merge of rust-lang#10990 - y21:issue8634-partial, r=blyxyas,xFrednet
[`single_match`]: don't lint if block contains comments Fixes rust-lang#8634 It now ignores matches with a comment in the "else" arm changelog: [`single_match`]: don't lint if block contains comments
2 parents 8fd021f + 2e856fa commit 5da6174

File tree

4 files changed

+105
-4
lines changed

4 files changed

+105
-4
lines changed

clippy_lints/src/matches/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ declare_clippy_lint! {
3838
/// Checks for matches with a single arm where an `if let`
3939
/// will usually suffice.
4040
///
41+
/// This intentionally does not lint if there are comments
42+
/// inside of the other arm, so as to allow the user to document
43+
/// why having another explicit pattern with an empty body is necessary,
44+
/// or because the comments need to be preserved for other reasons.
45+
///
4146
/// ### Why is this bad?
4247
/// Just readability – `if let` nests less than a `match`.
4348
///

clippy_lints/src/matches/single_match.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,32 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::source::{expr_block, snippet};
2+
use clippy_utils::source::{expr_block, get_source_text, snippet};
33
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs};
44
use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs};
55
use core::cmp::max;
66
use rustc_errors::Applicability;
77
use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind};
88
use rustc_lint::LateContext;
99
use rustc_middle::ty::{self, Ty};
10-
use rustc_span::sym;
10+
use rustc_span::{sym, Span};
1111

1212
use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE};
1313

14+
/// Checks if there are comments contained within a span.
15+
/// This is a very "naive" check, as it just looks for the literal characters // and /* in the
16+
/// source text. This won't be accurate if there are potentially expressions contained within the
17+
/// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty
18+
/// match arms.
19+
fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
20+
if let Some(ff) = get_source_text(cx, span)
21+
&& let Some(text) = ff.as_str()
22+
{
23+
text.as_bytes().windows(2)
24+
.any(|w| w == b"//" || w == b"/*")
25+
} else {
26+
false
27+
}
28+
}
29+
1430
#[rustfmt::skip]
1531
pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
1632
if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
@@ -25,7 +41,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
2541
return;
2642
}
2743
let els = arms[1].body;
28-
let els = if is_unit_expr(peel_blocks(els)) {
44+
let els = if is_unit_expr(peel_blocks(els)) && !empty_arm_has_comment(cx, els.span) {
2945
None
3046
} else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
3147
if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
@@ -35,7 +51,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
3551
// block with 2+ statements or 1 expr and 1+ statement
3652
Some(els)
3753
} else {
38-
// not a block, don't lint
54+
// not a block or an emtpy block w/ comments, don't lint
3955
return;
4056
};
4157

tests/ui/single_match.fixed

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,43 @@ fn issue_10808(bar: Option<i32>) {
212212
}
213213
}
214214
}
215+
216+
mod issue8634 {
217+
struct SomeError(i32, i32);
218+
219+
fn foo(x: Result<i32, ()>) {
220+
match x {
221+
Ok(y) => {
222+
println!("Yay! {y}");
223+
},
224+
Err(()) => {
225+
// Ignore this error because blah blah blah.
226+
},
227+
}
228+
}
229+
230+
fn bar(x: Result<i32, SomeError>) {
231+
match x {
232+
Ok(y) => {
233+
println!("Yay! {y}");
234+
},
235+
Err(_) => {
236+
// TODO: Process the error properly.
237+
},
238+
}
239+
}
240+
241+
fn block_comment(x: Result<i32, SomeError>) {
242+
match x {
243+
Ok(y) => {
244+
println!("Yay! {y}");
245+
},
246+
Err(_) => {
247+
/*
248+
let's make sure that this also
249+
does not lint block comments.
250+
*/
251+
},
252+
}
253+
}
254+
}

tests/ui/single_match.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,3 +270,43 @@ fn issue_10808(bar: Option<i32>) {
270270
_ => {},
271271
}
272272
}
273+
274+
mod issue8634 {
275+
struct SomeError(i32, i32);
276+
277+
fn foo(x: Result<i32, ()>) {
278+
match x {
279+
Ok(y) => {
280+
println!("Yay! {y}");
281+
},
282+
Err(()) => {
283+
// Ignore this error because blah blah blah.
284+
},
285+
}
286+
}
287+
288+
fn bar(x: Result<i32, SomeError>) {
289+
match x {
290+
Ok(y) => {
291+
println!("Yay! {y}");
292+
},
293+
Err(_) => {
294+
// TODO: Process the error properly.
295+
},
296+
}
297+
}
298+
299+
fn block_comment(x: Result<i32, SomeError>) {
300+
match x {
301+
Ok(y) => {
302+
println!("Yay! {y}");
303+
},
304+
Err(_) => {
305+
/*
306+
let's make sure that this also
307+
does not lint block comments.
308+
*/
309+
},
310+
}
311+
}
312+
}

0 commit comments

Comments
 (0)