Skip to content

Commit c2922d1

Browse files
authored
Make collapsible_if recognize the let_chains feature (#14481)
Until `if let` chains are stabilized, we do not collapse them together or with other `if` expressions unless the `let_chains` feature is enabled. This is the case for example in Clippy sources. This was made possible by converting the `collapsible_if` to a late lint to get access to the set of enabled features. This allows this PR to supersede #14455 and no longer require an additional configuration option. The three commits are, in order: - a conversion of the existing early lint to a late lint, with no new feature or tests changes - the addition of the `let_chains` feature detection and action, and tests - the application of the enhanced lint to Clippy sources (136 files modified) changelog: [`collapsible_if`]: recognize the rust compiler `let_chains` feature r? @flip1995
2 parents 61b38e7 + 79c6911 commit c2922d1

File tree

144 files changed

+2160
-1956
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

144 files changed

+2160
-1956
lines changed

Diff for: clippy_dev/src/update_lints.rs

+38-38
Original file line numberDiff line numberDiff line change
@@ -402,53 +402,53 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
402402
}
403403
}
404404

405-
if path.exists() {
406-
if let Some(lint) = lints.iter().find(|l| l.name == name) {
407-
if lint.module == name {
408-
// The lint name is the same as the file, we can just delete the entire file
409-
fs::remove_file(path)?;
410-
} else {
411-
// We can't delete the entire file, just remove the declaration
412-
413-
if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) {
414-
// Remove clippy_lints/src/some_mod/some_lint.rs
415-
let mut lint_mod_path = path.to_path_buf();
416-
lint_mod_path.set_file_name(name);
417-
lint_mod_path.set_extension("rs");
405+
if path.exists()
406+
&& let Some(lint) = lints.iter().find(|l| l.name == name)
407+
{
408+
if lint.module == name {
409+
// The lint name is the same as the file, we can just delete the entire file
410+
fs::remove_file(path)?;
411+
} else {
412+
// We can't delete the entire file, just remove the declaration
418413

419-
let _ = fs::remove_file(lint_mod_path);
420-
}
414+
if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) {
415+
// Remove clippy_lints/src/some_mod/some_lint.rs
416+
let mut lint_mod_path = path.to_path_buf();
417+
lint_mod_path.set_file_name(name);
418+
lint_mod_path.set_extension("rs");
421419

422-
let mut content =
423-
fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy()));
420+
let _ = fs::remove_file(lint_mod_path);
421+
}
424422

425-
eprintln!(
426-
"warn: you will have to manually remove any code related to `{name}` from `{}`",
427-
path.display()
428-
);
423+
let mut content =
424+
fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy()));
429425

430-
assert!(
431-
content[lint.declaration_range.clone()].contains(&name.to_uppercase()),
432-
"error: `{}` does not contain lint `{}`'s declaration",
433-
path.display(),
434-
lint.name
435-
);
426+
eprintln!(
427+
"warn: you will have to manually remove any code related to `{name}` from `{}`",
428+
path.display()
429+
);
436430

437-
// Remove lint declaration (declare_clippy_lint!)
438-
content.replace_range(lint.declaration_range.clone(), "");
431+
assert!(
432+
content[lint.declaration_range.clone()].contains(&name.to_uppercase()),
433+
"error: `{}` does not contain lint `{}`'s declaration",
434+
path.display(),
435+
lint.name
436+
);
439437

440-
// Remove the module declaration (mod xyz;)
441-
let mod_decl = format!("\nmod {name};");
442-
content = content.replacen(&mod_decl, "", 1);
438+
// Remove lint declaration (declare_clippy_lint!)
439+
content.replace_range(lint.declaration_range.clone(), "");
443440

444-
remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content);
445-
fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy()));
446-
}
441+
// Remove the module declaration (mod xyz;)
442+
let mod_decl = format!("\nmod {name};");
443+
content = content.replacen(&mod_decl, "", 1);
447444

448-
remove_test_assets(name);
449-
remove_lint(name, lints);
450-
return Ok(true);
445+
remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content);
446+
fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy()));
451447
}
448+
449+
remove_test_assets(name);
450+
remove_lint(name, lints);
451+
return Ok(true);
452452
}
453453

454454
Ok(false)

Diff for: clippy_dev/src/utils.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ pub fn clippy_project_root() -> PathBuf {
3030
let current_dir = std::env::current_dir().unwrap();
3131
for path in current_dir.ancestors() {
3232
let result = fs::read_to_string(path.join("Cargo.toml"));
33-
if let Err(err) = &result {
34-
if err.kind() == io::ErrorKind::NotFound {
35-
continue;
36-
}
33+
if let Err(err) = &result
34+
&& err.kind() == io::ErrorKind::NotFound
35+
{
36+
continue;
3737
}
3838

3939
let content = result.unwrap();

Diff for: clippy_lints/src/arbitrary_source_item_ordering.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,11 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
263263
continue;
264264
}
265265

266-
if let Some(cur_v) = cur_v {
267-
if cur_v.ident.name.as_str() > variant.ident.name.as_str() && cur_v.span != variant.span {
268-
Self::lint_member_name(cx, &variant.ident, &cur_v.ident);
269-
}
266+
if let Some(cur_v) = cur_v
267+
&& cur_v.ident.name.as_str() > variant.ident.name.as_str()
268+
&& cur_v.span != variant.span
269+
{
270+
Self::lint_member_name(cx, &variant.ident, &cur_v.ident);
270271
}
271272
cur_v = Some(variant);
272273
}
@@ -278,10 +279,11 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
278279
continue;
279280
}
280281

281-
if let Some(cur_f) = cur_f {
282-
if cur_f.ident.name.as_str() > field.ident.name.as_str() && cur_f.span != field.span {
283-
Self::lint_member_name(cx, &field.ident, &cur_f.ident);
284-
}
282+
if let Some(cur_f) = cur_f
283+
&& cur_f.ident.name.as_str() > field.ident.name.as_str()
284+
&& cur_f.span != field.span
285+
{
286+
Self::lint_member_name(cx, &field.ident, &cur_f.ident);
285287
}
286288
cur_f = Some(field);
287289
}

Diff for: clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs

+12-11
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@ use rustc_span::{DUMMY_SP, sym};
88

99
pub(super) fn check(cx: &EarlyContext<'_>, name: Symbol, items: &[MetaItemInner]) {
1010
for lint in items {
11-
if let Some(lint_name) = extract_clippy_lint(lint) {
12-
if lint_name.as_str() == "restriction" && name != sym::allow {
13-
span_lint_and_help(
14-
cx,
15-
BLANKET_CLIPPY_RESTRICTION_LINTS,
16-
lint.span(),
17-
"`clippy::restriction` is not meant to be enabled as a group",
18-
None,
19-
"enable the restriction lints you need individually",
20-
);
21-
}
11+
if let Some(lint_name) = extract_clippy_lint(lint)
12+
&& lint_name.as_str() == "restriction"
13+
&& name != sym::allow
14+
{
15+
span_lint_and_help(
16+
cx,
17+
BLANKET_CLIPPY_RESTRICTION_LINTS,
18+
lint.span(),
19+
"`clippy::restriction` is not meant to be enabled as a group",
20+
None,
21+
"enable the restriction lints you need individually",
22+
);
2223
}
2324
}
2425
}

Diff for: clippy_lints/src/attrs/deprecated_semver.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ use rustc_span::Span;
66
use semver::Version;
77

88
pub(super) fn check(cx: &EarlyContext<'_>, span: Span, lit: &MetaItemLit) {
9-
if let LitKind::Str(is, _) = lit.kind {
10-
if is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok() {
11-
return;
12-
}
9+
if let LitKind::Str(is, _) = lit.kind
10+
&& (is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok())
11+
{
12+
return;
1313
}
1414
span_lint(
1515
cx,

Diff for: clippy_lints/src/attrs/mod.rs

+20-21
Original file line numberDiff line numberDiff line change
@@ -573,28 +573,27 @@ impl EarlyLintPass for PostExpansionEarlyAttributes {
573573
}
574574

575575
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
576-
if let Some(items) = &attr.meta_item_list() {
577-
if let Some(ident) = attr.ident() {
578-
if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) {
579-
allow_attributes::check(cx, attr);
580-
}
581-
if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION)
576+
if let Some(items) = &attr.meta_item_list()
577+
&& let Some(ident) = attr.ident()
578+
{
579+
if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) {
580+
allow_attributes::check(cx, attr);
581+
}
582+
if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) {
583+
allow_attributes_without_reason::check(cx, ident.name, items, attr);
584+
}
585+
if is_lint_level(ident.name, attr.id) {
586+
blanket_clippy_restriction_lints::check(cx, ident.name, items);
587+
}
588+
if items.is_empty() || !attr.has_name(sym::deprecated) {
589+
return;
590+
}
591+
for item in items {
592+
if let MetaItemInner::MetaItem(mi) = &item
593+
&& let MetaItemKind::NameValue(lit) = &mi.kind
594+
&& mi.has_name(sym::since)
582595
{
583-
allow_attributes_without_reason::check(cx, ident.name, items, attr);
584-
}
585-
if is_lint_level(ident.name, attr.id) {
586-
blanket_clippy_restriction_lints::check(cx, ident.name, items);
587-
}
588-
if items.is_empty() || !attr.has_name(sym::deprecated) {
589-
return;
590-
}
591-
for item in items {
592-
if let MetaItemInner::MetaItem(mi) = &item
593-
&& let MetaItemKind::NameValue(lit) = &mi.kind
594-
&& mi.has_name(sym::since)
595-
{
596-
deprecated_semver::check(cx, item.span(), lit);
597-
}
596+
deprecated_semver::check(cx, item.span(), lit);
598597
}
599598
}
600599
}

Diff for: clippy_lints/src/attrs/useless_attribute.rs

+65-65
Original file line numberDiff line numberDiff line change
@@ -14,75 +14,75 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
1414
if attr.span.in_external_macro(cx.sess().source_map()) {
1515
return;
1616
}
17-
if let Some(lint_list) = &attr.meta_item_list() {
18-
if attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id)) {
19-
for lint in lint_list {
20-
match item.kind {
21-
ItemKind::Use(..) => {
22-
let (namespace @ (Some(sym::clippy) | None), Some(name)) = namespace_and_lint(lint) else {
23-
return;
24-
};
17+
if let Some(lint_list) = &attr.meta_item_list()
18+
&& attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id))
19+
{
20+
for lint in lint_list {
21+
match item.kind {
22+
ItemKind::Use(..) => {
23+
let (namespace @ (Some(sym::clippy) | None), Some(name)) = namespace_and_lint(lint) else {
24+
return;
25+
};
2526

26-
if namespace.is_none()
27-
&& matches!(
28-
name.as_str(),
29-
"ambiguous_glob_reexports"
30-
| "dead_code"
31-
| "deprecated"
32-
| "hidden_glob_reexports"
33-
| "unreachable_pub"
34-
| "unused"
35-
| "unused_braces"
36-
| "unused_import_braces"
37-
| "unused_imports"
38-
)
39-
{
40-
return;
41-
}
27+
if namespace.is_none()
28+
&& matches!(
29+
name.as_str(),
30+
"ambiguous_glob_reexports"
31+
| "dead_code"
32+
| "deprecated"
33+
| "hidden_glob_reexports"
34+
| "unreachable_pub"
35+
| "unused"
36+
| "unused_braces"
37+
| "unused_import_braces"
38+
| "unused_imports"
39+
)
40+
{
41+
return;
42+
}
4243

43-
if namespace == Some(sym::clippy)
44-
&& matches!(
45-
name.as_str(),
46-
"wildcard_imports"
47-
| "enum_glob_use"
48-
| "redundant_pub_crate"
49-
| "macro_use_imports"
50-
| "unsafe_removed_from_name"
51-
| "module_name_repetitions"
52-
| "single_component_path_imports"
53-
| "disallowed_types"
54-
| "unused_trait_names"
55-
)
56-
{
57-
return;
58-
}
59-
},
60-
ItemKind::ExternCrate(..) => {
61-
if is_word(lint, sym::unused_imports) && skip_unused_imports {
62-
return;
63-
}
64-
if is_word(lint, sym!(unused_extern_crates)) {
65-
return;
66-
}
67-
},
68-
_ => {},
69-
}
44+
if namespace == Some(sym::clippy)
45+
&& matches!(
46+
name.as_str(),
47+
"wildcard_imports"
48+
| "enum_glob_use"
49+
| "redundant_pub_crate"
50+
| "macro_use_imports"
51+
| "unsafe_removed_from_name"
52+
| "module_name_repetitions"
53+
| "single_component_path_imports"
54+
| "disallowed_types"
55+
| "unused_trait_names"
56+
)
57+
{
58+
return;
59+
}
60+
},
61+
ItemKind::ExternCrate(..) => {
62+
if is_word(lint, sym::unused_imports) && skip_unused_imports {
63+
return;
64+
}
65+
if is_word(lint, sym!(unused_extern_crates)) {
66+
return;
67+
}
68+
},
69+
_ => {},
7070
}
71-
let line_span = first_line_of_span(cx, attr.span);
71+
}
72+
let line_span = first_line_of_span(cx, attr.span);
7273

73-
if let Some(src) = line_span.get_source_text(cx) {
74-
if src.contains("#[") {
75-
#[expect(clippy::collapsible_span_lint_calls)]
76-
span_lint_and_then(cx, USELESS_ATTRIBUTE, line_span, "useless lint attribute", |diag| {
77-
diag.span_suggestion(
78-
line_span,
79-
"if you just forgot a `!`, use",
80-
src.replacen("#[", "#![", 1),
81-
Applicability::MaybeIncorrect,
82-
);
83-
});
84-
}
85-
}
74+
if let Some(src) = line_span.get_source_text(cx)
75+
&& src.contains("#[")
76+
{
77+
#[expect(clippy::collapsible_span_lint_calls)]
78+
span_lint_and_then(cx, USELESS_ATTRIBUTE, line_span, "useless lint attribute", |diag| {
79+
diag.span_suggestion(
80+
line_span,
81+
"if you just forgot a `!`, use",
82+
src.replacen("#[", "#![", 1),
83+
Applicability::MaybeIncorrect,
84+
);
85+
});
8686
}
8787
}
8888
}

Diff for: clippy_lints/src/await_holding_invalid.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -192,10 +192,9 @@ impl<'tcx> LateLintPass<'tcx> for AwaitHolding {
192192
def_id,
193193
..
194194
}) = expr.kind
195+
&& let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(*def_id)
195196
{
196-
if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(*def_id) {
197-
self.check_interior_types(cx, coroutine_layout);
198-
}
197+
self.check_interior_types(cx, coroutine_layout);
199198
}
200199
}
201200
}

0 commit comments

Comments
 (0)