Skip to content

Commit 663ef9b

Browse files
authored
fix(rc_buffer): don't touch the path to Rc/Arc in the suggestion (#15803)
Fixes #15802 changelog: [`rc_buffer`]: don't touch the path to `Rc`/`Arc` in the suggestion
2 parents 4016c0f + f2e6667 commit 663ef9b

File tree

7 files changed

+243
-150
lines changed

7 files changed

+243
-150
lines changed

clippy_lints/src/types/rc_buffer.rs

Lines changed: 55 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,74 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::qpath_generic_tys;
3-
use clippy_utils::res::{MaybeDef, MaybeResPath};
3+
use clippy_utils::res::MaybeResPath;
44
use clippy_utils::source::snippet_with_applicability;
55
use rustc_errors::Applicability;
66
use rustc_hir::def_id::DefId;
7-
use rustc_hir::{self as hir, QPath, TyKind};
7+
use rustc_hir::{QPath, Ty, TyKind};
88
use rustc_lint::LateContext;
99
use rustc_span::symbol::sym;
10+
use std::borrow::Cow;
11+
use std::fmt;
1012

1113
use super::RC_BUFFER;
1214

13-
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
14-
let app = Applicability::Unspecified;
15-
let name = cx.tcx.get_diagnostic_name(def_id);
16-
if name == Some(sym::Rc) {
17-
if let Some(alternate) = match_buffer_type(cx, qpath) {
18-
#[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
19-
span_lint_and_then(
20-
cx,
21-
RC_BUFFER,
22-
hir_ty.span,
23-
"usage of `Rc<T>` when T is a buffer type",
24-
|diag| {
25-
diag.span_suggestion(hir_ty.span, "try", format!("Rc<{alternate}>"), app);
26-
},
27-
);
28-
} else {
29-
let Some(ty) = qpath_generic_tys(qpath).next() else {
30-
return false;
31-
};
32-
if !ty.basic_res().is_diag_item(cx, sym::Vec) {
33-
return false;
34-
}
35-
let TyKind::Path(qpath) = &ty.kind else { return false };
36-
let inner_span = match qpath_generic_tys(qpath).next() {
37-
Some(ty) => ty.span,
38-
None => return false,
39-
};
40-
span_lint_and_then(
41-
cx,
42-
RC_BUFFER,
43-
hir_ty.span,
44-
"usage of `Rc<T>` when T is a buffer type",
45-
|diag| {
46-
let mut applicability = app;
47-
diag.span_suggestion(
48-
hir_ty.span,
49-
"try",
50-
format!(
51-
"Rc<[{}]>",
52-
snippet_with_applicability(cx, inner_span, "..", &mut applicability)
53-
),
54-
app,
55-
);
56-
},
57-
);
58-
return true;
59-
}
60-
} else if name == Some(sym::Arc) {
61-
if let Some(alternate) = match_buffer_type(cx, qpath) {
62-
#[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
63-
span_lint_and_then(
64-
cx,
65-
RC_BUFFER,
66-
hir_ty.span,
67-
"usage of `Arc<T>` when T is a buffer type",
68-
|diag| {
69-
diag.span_suggestion(hir_ty.span, "try", format!("Arc<{alternate}>"), app);
70-
},
71-
);
72-
} else if let Some(ty) = qpath_generic_tys(qpath).next() {
73-
if !ty.basic_res().is_diag_item(cx, sym::Vec) {
74-
return false;
75-
}
76-
let TyKind::Path(qpath) = &ty.kind else { return false };
77-
let inner_span = match qpath_generic_tys(qpath).next() {
78-
Some(ty) => ty.span,
79-
None => return false,
80-
};
81-
span_lint_and_then(
82-
cx,
83-
RC_BUFFER,
84-
hir_ty.span,
85-
"usage of `Arc<T>` when T is a buffer type",
86-
|diag| {
87-
let mut applicability = app;
88-
diag.span_suggestion(
89-
hir_ty.span,
90-
"try",
91-
format!(
92-
"Arc<[{}]>",
93-
snippet_with_applicability(cx, inner_span, "..", &mut applicability)
94-
),
95-
app,
96-
);
97-
},
98-
);
99-
return true;
100-
}
15+
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
16+
let mut app = Applicability::Unspecified;
17+
let kind = match cx.tcx.get_diagnostic_name(def_id) {
18+
Some(sym::Rc) => RcKind::Rc,
19+
Some(sym::Arc) => RcKind::Arc,
20+
_ => return false,
21+
};
22+
if let Some(ty) = qpath_generic_tys(qpath).next()
23+
&& let Some(alternate) = match_buffer_type(cx, ty, &mut app)
24+
{
25+
span_lint_and_then(
26+
cx,
27+
RC_BUFFER,
28+
hir_ty.span,
29+
format!("usage of `{kind}<T>` when `T` is a buffer type"),
30+
|diag| {
31+
diag.span_suggestion_verbose(ty.span, "try", alternate, app);
32+
},
33+
);
34+
true
35+
} else {
36+
false
10137
}
38+
}
39+
40+
enum RcKind {
41+
Rc,
42+
Arc,
43+
}
10244

103-
false
45+
impl fmt::Display for RcKind {
46+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47+
match self {
48+
Self::Rc => f.write_str("Rc"),
49+
Self::Arc => f.write_str("Arc"),
50+
}
51+
}
10452
}
10553

106-
fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
107-
let ty = qpath_generic_tys(qpath).next()?;
54+
fn match_buffer_type(
55+
cx: &LateContext<'_>,
56+
ty: &Ty<'_>,
57+
applicability: &mut Applicability,
58+
) -> Option<Cow<'static, str>> {
10859
let id = ty.basic_res().opt_def_id()?;
10960
let path = match cx.tcx.get_diagnostic_name(id) {
110-
Some(sym::OsString) => "std::ffi::OsStr",
111-
Some(sym::PathBuf) => "std::path::Path",
112-
_ if Some(id) == cx.tcx.lang_items().string() => "str",
61+
Some(sym::OsString) => "std::ffi::OsStr".into(),
62+
Some(sym::PathBuf) => "std::path::Path".into(),
63+
Some(sym::Vec) => {
64+
let TyKind::Path(vec_qpath) = &ty.kind else {
65+
return None;
66+
};
67+
let vec_generic_ty = qpath_generic_tys(vec_qpath).next()?;
68+
let snippet = snippet_with_applicability(cx, vec_generic_ty.span, "_", applicability);
69+
format!("[{snippet}]").into()
70+
},
71+
_ if Some(id) == cx.tcx.lang_items().string() => "str".into(),
11372
_ => return None,
11473
};
11574
Some(path)

tests/ui/rc_buffer.fixed

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#![warn(clippy::rc_buffer)]
2-
#![allow(dead_code, unused_imports)]
32

43
use std::cell::RefCell;
54
use std::ffi::OsString;
@@ -32,4 +31,9 @@ fn func_bad4(_: Rc<std::ffi::OsStr>) {}
3231
// does not trigger lint
3332
fn func_good1(_: Rc<RefCell<String>>) {}
3433

34+
mod issue_15802 {
35+
fn foo(_: std::rc::Rc<[u8]>) {}
36+
//~^ rc_buffer
37+
}
38+
3539
fn main() {}

tests/ui/rc_buffer.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#![warn(clippy::rc_buffer)]
2-
#![allow(dead_code, unused_imports)]
32

43
use std::cell::RefCell;
54
use std::ffi::OsString;
@@ -32,4 +31,9 @@ fn func_bad4(_: Rc<OsString>) {}
3231
// does not trigger lint
3332
fn func_good1(_: Rc<RefCell<String>>) {}
3433

34+
mod issue_15802 {
35+
fn foo(_: std::rc::Rc<Vec<u8>>) {}
36+
//~^ rc_buffer
37+
}
38+
3539
fn main() {}

tests/ui/rc_buffer.stderr

Lines changed: 84 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,112 @@
1-
error: usage of `Rc<T>` when T is a buffer type
2-
--> tests/ui/rc_buffer.rs:11:11
1+
error: usage of `Rc<T>` when `T` is a buffer type
2+
--> tests/ui/rc_buffer.rs:10:11
33
|
44
LL | bad1: Rc<String>,
5-
| ^^^^^^^^^^ help: try: `Rc<str>`
5+
| ^^^^^^^^^^
66
|
77
= note: `-D clippy::rc-buffer` implied by `-D warnings`
88
= help: to override `-D warnings` add `#[allow(clippy::rc_buffer)]`
9+
help: try
10+
|
11+
LL - bad1: Rc<String>,
12+
LL + bad1: Rc<str>,
13+
|
914

10-
error: usage of `Rc<T>` when T is a buffer type
11-
--> tests/ui/rc_buffer.rs:13:11
15+
error: usage of `Rc<T>` when `T` is a buffer type
16+
--> tests/ui/rc_buffer.rs:12:11
1217
|
1318
LL | bad2: Rc<PathBuf>,
14-
| ^^^^^^^^^^^ help: try: `Rc<std::path::Path>`
19+
| ^^^^^^^^^^^
20+
|
21+
help: try
22+
|
23+
LL - bad2: Rc<PathBuf>,
24+
LL + bad2: Rc<std::path::Path>,
25+
|
1526

16-
error: usage of `Rc<T>` when T is a buffer type
17-
--> tests/ui/rc_buffer.rs:15:11
27+
error: usage of `Rc<T>` when `T` is a buffer type
28+
--> tests/ui/rc_buffer.rs:14:11
1829
|
1930
LL | bad3: Rc<Vec<u8>>,
20-
| ^^^^^^^^^^^ help: try: `Rc<[u8]>`
31+
| ^^^^^^^^^^^
32+
|
33+
help: try
34+
|
35+
LL - bad3: Rc<Vec<u8>>,
36+
LL + bad3: Rc<[u8]>,
37+
|
2138

22-
error: usage of `Rc<T>` when T is a buffer type
23-
--> tests/ui/rc_buffer.rs:17:11
39+
error: usage of `Rc<T>` when `T` is a buffer type
40+
--> tests/ui/rc_buffer.rs:16:11
2441
|
2542
LL | bad4: Rc<OsString>,
26-
| ^^^^^^^^^^^^ help: try: `Rc<std::ffi::OsStr>`
43+
| ^^^^^^^^^^^^
44+
|
45+
help: try
46+
|
47+
LL - bad4: Rc<OsString>,
48+
LL + bad4: Rc<std::ffi::OsStr>,
49+
|
2750

28-
error: usage of `Rc<T>` when T is a buffer type
29-
--> tests/ui/rc_buffer.rs:24:17
51+
error: usage of `Rc<T>` when `T` is a buffer type
52+
--> tests/ui/rc_buffer.rs:23:17
3053
|
3154
LL | fn func_bad1(_: Rc<String>) {}
32-
| ^^^^^^^^^^ help: try: `Rc<str>`
55+
| ^^^^^^^^^^
56+
|
57+
help: try
58+
|
59+
LL - fn func_bad1(_: Rc<String>) {}
60+
LL + fn func_bad1(_: Rc<str>) {}
61+
|
3362

34-
error: usage of `Rc<T>` when T is a buffer type
35-
--> tests/ui/rc_buffer.rs:26:17
63+
error: usage of `Rc<T>` when `T` is a buffer type
64+
--> tests/ui/rc_buffer.rs:25:17
3665
|
3766
LL | fn func_bad2(_: Rc<PathBuf>) {}
38-
| ^^^^^^^^^^^ help: try: `Rc<std::path::Path>`
67+
| ^^^^^^^^^^^
68+
|
69+
help: try
70+
|
71+
LL - fn func_bad2(_: Rc<PathBuf>) {}
72+
LL + fn func_bad2(_: Rc<std::path::Path>) {}
73+
|
3974

40-
error: usage of `Rc<T>` when T is a buffer type
41-
--> tests/ui/rc_buffer.rs:28:17
75+
error: usage of `Rc<T>` when `T` is a buffer type
76+
--> tests/ui/rc_buffer.rs:27:17
4277
|
4378
LL | fn func_bad3(_: Rc<Vec<u8>>) {}
44-
| ^^^^^^^^^^^ help: try: `Rc<[u8]>`
79+
| ^^^^^^^^^^^
80+
|
81+
help: try
82+
|
83+
LL - fn func_bad3(_: Rc<Vec<u8>>) {}
84+
LL + fn func_bad3(_: Rc<[u8]>) {}
85+
|
4586

46-
error: usage of `Rc<T>` when T is a buffer type
47-
--> tests/ui/rc_buffer.rs:30:17
87+
error: usage of `Rc<T>` when `T` is a buffer type
88+
--> tests/ui/rc_buffer.rs:29:17
4889
|
4990
LL | fn func_bad4(_: Rc<OsString>) {}
50-
| ^^^^^^^^^^^^ help: try: `Rc<std::ffi::OsStr>`
91+
| ^^^^^^^^^^^^
92+
|
93+
help: try
94+
|
95+
LL - fn func_bad4(_: Rc<OsString>) {}
96+
LL + fn func_bad4(_: Rc<std::ffi::OsStr>) {}
97+
|
98+
99+
error: usage of `Rc<T>` when `T` is a buffer type
100+
--> tests/ui/rc_buffer.rs:35:15
101+
|
102+
LL | fn foo(_: std::rc::Rc<Vec<u8>>) {}
103+
| ^^^^^^^^^^^^^^^^^^^^
104+
|
105+
help: try
106+
|
107+
LL - fn foo(_: std::rc::Rc<Vec<u8>>) {}
108+
LL + fn foo(_: std::rc::Rc<[u8]>) {}
109+
|
51110

52-
error: aborting due to 8 previous errors
111+
error: aborting due to 9 previous errors
53112

tests/ui/rc_buffer_arc.fixed

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#![warn(clippy::rc_buffer)]
2-
#![allow(dead_code, unused_imports)]
32

43
use std::ffi::OsString;
54
use std::path::PathBuf;
@@ -31,4 +30,9 @@ fn func_bad4(_: Arc<std::ffi::OsStr>) {}
3130
// does not trigger lint
3231
fn func_good1(_: Arc<Mutex<String>>) {}
3332

33+
mod issue_15802 {
34+
fn foo(_: std::sync::Arc<[u8]>) {}
35+
//~^ rc_buffer
36+
}
37+
3438
fn main() {}

tests/ui/rc_buffer_arc.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#![warn(clippy::rc_buffer)]
2-
#![allow(dead_code, unused_imports)]
32

43
use std::ffi::OsString;
54
use std::path::PathBuf;
@@ -31,4 +30,9 @@ fn func_bad4(_: Arc<OsString>) {}
3130
// does not trigger lint
3231
fn func_good1(_: Arc<Mutex<String>>) {}
3332

33+
mod issue_15802 {
34+
fn foo(_: std::sync::Arc<Vec<u8>>) {}
35+
//~^ rc_buffer
36+
}
37+
3438
fn main() {}

0 commit comments

Comments
 (0)