Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 9ec5428

Browse files
committed
Add 5 other container types and start testing
1 parent df65d21 commit 9ec5428

File tree

5 files changed

+112
-20
lines changed

5 files changed

+112
-20
lines changed

clippy_lints/src/methods/clear_with_drain.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,45 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::is_range_full;
33
use clippy_utils::ty::is_type_diagnostic_item;
44
use rustc_errors::Applicability;
5+
use rustc_hir as hir;
56
use rustc_hir::{Expr, ExprKind, QPath};
67
use rustc_lint::LateContext;
78
use rustc_span::symbol::sym;
89
use rustc_span::Span;
910

1011
use super::CLEAR_WITH_DRAIN;
1112

12-
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: &Expr<'_>) {
13-
let ty = cx.typeck_results().expr_ty(recv);
14-
if is_type_diagnostic_item(cx, ty, sym::Vec)
15-
&& let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind
16-
&& is_range_full(cx, arg, Some(container_path))
13+
const ACCEPTABLE_TYPES_WITH_ARG: [rustc_span::Symbol; 3] = [sym::String, sym::Vec, sym::VecDeque];
14+
15+
const ACCEPTABLE_TYPES_WITHOUT_ARG: [rustc_span::Symbol; 3] = [sym::BinaryHeap, sym::HashMap, sym::HashSet];
16+
17+
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: Option<&Expr<'_>>) {
18+
if let Some(arg) = arg {
19+
if match_acceptable_type(cx, recv, &ACCEPTABLE_TYPES_WITH_ARG)
20+
&& let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind
21+
&& is_range_full(cx, arg, Some(container_path))
22+
{
23+
suggest(cx, expr, recv, span);
24+
}
25+
} else if match_acceptable_type(cx, recv, &ACCEPTABLE_TYPES_WITHOUT_ARG) {
26+
suggest(cx, expr, recv, span);
27+
}
28+
}
29+
30+
fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, types: &[rustc_span::Symbol]) -> bool {
31+
let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs();
32+
types.iter().any(|&ty| is_type_diagnostic_item(cx, expr_ty, ty))
33+
}
34+
35+
fn suggest(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) {
36+
if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
37+
&& let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did())
1738
{
1839
span_lint_and_sugg(
1940
cx,
2041
CLEAR_WITH_DRAIN,
2142
span.with_hi(expr.span.hi()),
22-
"`drain` used to clear a `Vec`",
43+
&format!("`drain` used to clear a `{}`", ty_name),
2344
"try",
2445
"clear()".to_string(),
2546
Applicability::MachineApplicable,

clippy_lints/src/methods/mod.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3589,12 +3589,13 @@ impl Methods {
35893589
Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
35903590
_ => {},
35913591
},
3592-
("drain", [arg]) => {
3593-
if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id)
3594-
&& matches!(kind, StmtKind::Semi(_))
3592+
("drain", ..) => {
3593+
if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id)
3594+
&& matches!(kind, StmtKind::Semi(_))
3595+
&& args.len() <= 1
35953596
{
3596-
clear_with_drain::check(cx, expr, recv, span, arg);
3597-
} else {
3597+
clear_with_drain::check(cx, expr, recv, span, args.first());
3598+
} else if let [arg] = args {
35983599
iter_with_drain::check(cx, expr, recv, span, arg);
35993600
}
36003601
},

tests/ui/clear_with_drain.fixed

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
#![allow(unused)]
33
#![warn(clippy::clear_with_drain)]
44

5+
use std::collections::BinaryHeap;
6+
use std::collections::HashMap;
7+
use std::collections::HashSet;
8+
use std::collections::VecDeque;
9+
510
fn range() {
611
let mut v = vec![1, 2, 3];
712
let iter = v.drain(0..v.len()); // Yay
@@ -83,4 +88,22 @@ fn partial_drains() {
8388
let w: Vec<i8> = v.drain(1..v.len() - 1).collect(); // Yay
8489
}
8590

86-
fn main() {}
91+
fn main() {
92+
let mut deque: VecDeque<_> = [1, 2, 3].into();
93+
deque.clear();
94+
95+
let mut set = HashSet::from([1, 2, 3]);
96+
set.clear();
97+
98+
let mut a = HashMap::new();
99+
a.insert(1, "a");
100+
a.insert(2, "b");
101+
a.clear();
102+
103+
let mut heap = BinaryHeap::from([1, 3]);
104+
heap.clear();
105+
106+
// Not firing for now because `String` is not reckognized by `is_type_diagnostic_item`
107+
let mut s = String::from("α is alpha, β is beta");
108+
s.drain(..);
109+
}

tests/ui/clear_with_drain.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
#![allow(unused)]
33
#![warn(clippy::clear_with_drain)]
44

5+
use std::collections::BinaryHeap;
6+
use std::collections::HashMap;
7+
use std::collections::HashSet;
8+
use std::collections::VecDeque;
9+
510
fn range() {
611
let mut v = vec![1, 2, 3];
712
let iter = v.drain(0..v.len()); // Yay
@@ -83,4 +88,22 @@ fn partial_drains() {
8388
let w: Vec<i8> = v.drain(1..v.len() - 1).collect(); // Yay
8489
}
8590

86-
fn main() {}
91+
fn main() {
92+
let mut deque: VecDeque<_> = [1, 2, 3].into();
93+
deque.drain(..);
94+
95+
let mut set = HashSet::from([1, 2, 3]);
96+
set.drain();
97+
98+
let mut a = HashMap::new();
99+
a.insert(1, "a");
100+
a.insert(2, "b");
101+
a.drain();
102+
103+
let mut heap = BinaryHeap::from([1, 3]);
104+
heap.drain();
105+
106+
// Not firing for now because `String` is not reckognized by `is_type_diagnostic_item`
107+
let mut s = String::from("α is alpha, β is beta");
108+
s.drain(..);
109+
}

tests/ui/clear_with_drain.stderr

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,64 @@
11
error: `drain` used to clear a `Vec`
2-
--> $DIR/clear_with_drain.rs:17:7
2+
--> $DIR/clear_with_drain.rs:22:7
33
|
44
LL | v.drain(0..v.len()); // Nay
55
| ^^^^^^^^^^^^^^^^^ help: try: `clear()`
66
|
77
= note: `-D clippy::clear-with-drain` implied by `-D warnings`
88

99
error: `drain` used to clear a `Vec`
10-
--> $DIR/clear_with_drain.rs:20:7
10+
--> $DIR/clear_with_drain.rs:25:7
1111
|
1212
LL | v.drain(usize::MIN..v.len()); // Nay
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()`
1414

1515
error: `drain` used to clear a `Vec`
16-
--> $DIR/clear_with_drain.rs:35:7
16+
--> $DIR/clear_with_drain.rs:40:7
1717
|
1818
LL | v.drain(0..); // Nay
1919
| ^^^^^^^^^^ help: try: `clear()`
2020

2121
error: `drain` used to clear a `Vec`
22-
--> $DIR/clear_with_drain.rs:38:7
22+
--> $DIR/clear_with_drain.rs:43:7
2323
|
2424
LL | v.drain(usize::MIN..); // Nay
2525
| ^^^^^^^^^^^^^^^^^^^ help: try: `clear()`
2626

2727
error: `drain` used to clear a `Vec`
28-
--> $DIR/clear_with_drain.rs:52:7
28+
--> $DIR/clear_with_drain.rs:57:7
2929
|
3030
LL | v.drain(..); // Nay
3131
| ^^^^^^^^^ help: try: `clear()`
3232

3333
error: `drain` used to clear a `Vec`
34-
--> $DIR/clear_with_drain.rs:66:7
34+
--> $DIR/clear_with_drain.rs:71:7
3535
|
3636
LL | v.drain(..v.len()); // Nay
3737
| ^^^^^^^^^^^^^^^^ help: try: `clear()`
3838

39-
error: aborting due to 6 previous errors
39+
error: `drain` used to clear a `VecDeque`
40+
--> $DIR/clear_with_drain.rs:93:11
41+
|
42+
LL | deque.drain(..);
43+
| ^^^^^^^^^ help: try: `clear()`
44+
45+
error: `drain` used to clear a `HashSet`
46+
--> $DIR/clear_with_drain.rs:96:9
47+
|
48+
LL | set.drain();
49+
| ^^^^^^^ help: try: `clear()`
50+
51+
error: `drain` used to clear a `HashMap`
52+
--> $DIR/clear_with_drain.rs:101:7
53+
|
54+
LL | a.drain();
55+
| ^^^^^^^ help: try: `clear()`
56+
57+
error: `drain` used to clear a `BinaryHeap`
58+
--> $DIR/clear_with_drain.rs:104:10
59+
|
60+
LL | heap.drain();
61+
| ^^^^^^^ help: try: `clear()`
62+
63+
error: aborting due to 10 previous errors
4064

0 commit comments

Comments
 (0)