Skip to content

Commit f1f1165

Browse files
authored
fix must_use_unit suggestion when there're multiple attributes (#13830)
fix #12320 When there're multiple attributes, clippy suggests leaving an extra comma and it makes an error. changelog: [`must_use_unit`]: No longer make incorrect suggestions when multiple attributes present.
2 parents 1dddeab + e7c27c6 commit f1f1165

File tree

4 files changed

+75
-13
lines changed

4 files changed

+75
-13
lines changed

clippy_lints/src/functions/must_use.rs

+46-12
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
2929
let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
3030
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
3131
if let Some(attr) = attr {
32-
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig);
32+
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
3333
} else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
3434
check_must_use_candidate(
3535
cx,
@@ -51,7 +51,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
5151
let attrs = cx.tcx.hir().attrs(item.hir_id());
5252
let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
5353
if let Some(attr) = attr {
54-
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig);
54+
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
5555
} else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
5656
check_must_use_candidate(
5757
cx,
@@ -74,7 +74,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
7474
let attrs = cx.tcx.hir().attrs(item.hir_id());
7575
let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
7676
if let Some(attr) = attr {
77-
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig);
77+
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
7878
} else if let hir::TraitFn::Provided(eid) = *eid {
7979
let body = cx.tcx.hir().body(eid);
8080
if attr.is_none() && is_public && !is_proc_macro(attrs) {
@@ -92,28 +92,62 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
9292
}
9393
}
9494

95+
#[allow(clippy::too_many_arguments)]
9596
fn check_needless_must_use(
9697
cx: &LateContext<'_>,
9798
decl: &hir::FnDecl<'_>,
9899
item_id: hir::OwnerId,
99100
item_span: Span,
100101
fn_header_span: Span,
101102
attr: &Attribute,
103+
attrs: &[Attribute],
102104
sig: &FnSig<'_>,
103105
) {
104106
if in_external_macro(cx.sess(), item_span) {
105107
return;
106108
}
107109
if returns_unit(decl) {
108-
span_lint_and_then(
109-
cx,
110-
MUST_USE_UNIT,
111-
fn_header_span,
112-
"this unit-returning function has a `#[must_use]` attribute",
113-
|diag| {
114-
diag.span_suggestion(attr.span, "remove the attribute", "", Applicability::MachineApplicable);
115-
},
116-
);
110+
if attrs.len() == 1 {
111+
span_lint_and_then(
112+
cx,
113+
MUST_USE_UNIT,
114+
fn_header_span,
115+
"this unit-returning function has a `#[must_use]` attribute",
116+
|diag| {
117+
diag.span_suggestion(attr.span, "remove the attribute", "", Applicability::MachineApplicable);
118+
},
119+
);
120+
} else {
121+
// When there are multiple attributes, it is not sufficient to simply make `must_use` empty, see
122+
// issue #12320.
123+
span_lint_and_then(
124+
cx,
125+
MUST_USE_UNIT,
126+
fn_header_span,
127+
"this unit-returning function has a `#[must_use]` attribute",
128+
|diag| {
129+
let mut attrs_without_must_use = attrs.to_vec();
130+
attrs_without_must_use.retain(|a| a.id != attr.id);
131+
let sugg_str = attrs_without_must_use
132+
.iter()
133+
.map(|a| {
134+
if a.value_str().is_none() {
135+
return a.name_or_empty().to_string();
136+
}
137+
format!("{} = \"{}\"", a.name_or_empty(), a.value_str().unwrap())
138+
})
139+
.collect::<Vec<_>>()
140+
.join(", ");
141+
142+
diag.span_suggestion(
143+
attrs[0].span.with_hi(attrs[attrs.len() - 1].span.hi()),
144+
"change these attributes to",
145+
sugg_str,
146+
Applicability::MachineApplicable,
147+
);
148+
},
149+
);
150+
}
117151
} else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
118152
// Ignore async functions unless Future::Output type is a must_use type
119153
if sig.header.is_async() {

tests/ui/must_use_unit.fixed

+6
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,9 @@ fn main() {
2323
fn foo() {}
2424
);
2525
}
26+
27+
#[cfg_attr(all(), deprecated)]
28+
fn issue_12320() {}
29+
30+
#[cfg_attr(all(), deprecated, doc = "foo")]
31+
fn issue_12320_2() {}

tests/ui/must_use_unit.rs

+6
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,9 @@ fn main() {
2626
fn foo() {}
2727
);
2828
}
29+
30+
#[cfg_attr(all(), must_use, deprecated)]
31+
fn issue_12320() {}
32+
33+
#[cfg_attr(all(), deprecated, doc = "foo", must_use)]
34+
fn issue_12320_2() {}

tests/ui/must_use_unit.stderr

+17-1
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,21 @@ LL | #[must_use = "With note"]
2525
LL | pub fn must_use_with_note() {}
2626
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
2727

28-
error: aborting due to 3 previous errors
28+
error: this unit-returning function has a `#[must_use]` attribute
29+
--> tests/ui/must_use_unit.rs:31:1
30+
|
31+
LL | #[cfg_attr(all(), must_use, deprecated)]
32+
| -------------------- help: change these attributes to: `deprecated`
33+
LL | fn issue_12320() {}
34+
| ^^^^^^^^^^^^^^^^
35+
36+
error: this unit-returning function has a `#[must_use]` attribute
37+
--> tests/ui/must_use_unit.rs:34:1
38+
|
39+
LL | #[cfg_attr(all(), deprecated, doc = "foo", must_use)]
40+
| --------------------------------- help: change these attributes to: `deprecated, doc = "foo"`
41+
LL | fn issue_12320_2() {}
42+
| ^^^^^^^^^^^^^^^^^^
43+
44+
error: aborting due to 5 previous errors
2945

0 commit comments

Comments
 (0)