Skip to content

Commit 32aa07f

Browse files
committed
Fix false negative for Strings
`String` is not a diagnostic item and was thus not picked up by `is_type_diagnostic_item`, leading to a false negative for `collection_is_never_read`
1 parent 5b57e5c commit 32aa07f

File tree

3 files changed

+45
-7
lines changed

3 files changed

+45
-7
lines changed

clippy_lints/src/collection_is_never_read.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use clippy_utils::diagnostics::span_lint;
2-
use clippy_utils::ty::is_type_diagnostic_item;
2+
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
33
use clippy_utils::visitors::for_each_expr_with_closures;
44
use clippy_utils::{get_enclosing_block, get_parent_node, path_to_local_id};
55
use core::ops::ControlFlow;
6-
use rustc_hir::{Block, ExprKind, HirId, Local, Node, PatKind};
6+
use rustc_hir::{Block, ExprKind, HirId, LangItem, Local, Node, PatKind};
77
use rustc_lint::{LateContext, LateLintPass};
88
use rustc_session::{declare_lint_pass, declare_tool_lint};
99
use rustc_span::symbol::sym;
@@ -44,24 +44,23 @@ declare_clippy_lint! {
4444
}
4545
declare_lint_pass!(CollectionIsNeverRead => [COLLECTION_IS_NEVER_READ]);
4646

47-
static COLLECTIONS: [Symbol; 10] = [
47+
// Add `String` here when it is added to diagnostic items
48+
static COLLECTIONS: [Symbol; 9] = [
4849
sym::BTreeMap,
4950
sym::BTreeSet,
5051
sym::BinaryHeap,
5152
sym::HashMap,
5253
sym::HashSet,
5354
sym::LinkedList,
5455
sym::Option,
55-
sym::String,
5656
sym::Vec,
5757
sym::VecDeque,
5858
];
5959

6060
impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
6161
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
6262
// Look for local variables whose type is a container. Search surrounding bock for read access.
63-
let ty = cx.typeck_results().pat_ty(local.pat);
64-
if COLLECTIONS.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym))
63+
if match_acceptable_type(cx, local, &COLLECTIONS)
6564
&& let PatKind::Binding(_, local_id, _, _) = local.pat.kind
6665
&& let Some(enclosing_block) = get_enclosing_block(cx, local.hir_id)
6766
&& has_no_read_access(cx, local_id, enclosing_block)
@@ -71,6 +70,13 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
7170
}
7271
}
7372

73+
fn match_acceptable_type(cx: &LateContext<'_>, local: &Local<'_>, collections: &[rustc_span::Symbol]) -> bool {
74+
let ty = cx.typeck_results().pat_ty(local.pat);
75+
collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym))
76+
// String type is a lang item but not a diagnostic item for now so we need a separate check
77+
|| is_type_lang_item(cx, ty, LangItem::String)
78+
}
79+
7480
fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Block<'tcx>) -> bool {
7581
let mut has_access = false;
7682
let mut has_read_access = false;

tests/ui/collection_is_never_read.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,23 @@ fn function_argument() {
163163
let x = vec![1, 2, 3]; // Ok
164164
foo(&x);
165165
}
166+
167+
fn string() {
168+
// Do lint (write without read)
169+
let mut s = String::new();
170+
s.push_str("Hello, World!");
171+
172+
// Do not lint (read without write)
173+
let mut s = String::from("Hello, World!");
174+
let _ = s.len();
175+
176+
// Do not lint (write and read)
177+
let mut s = String::from("Hello, World!");
178+
s.push_str("foo, bar");
179+
let _ = s.len();
180+
181+
// Do lint the first line, but not the second
182+
let mut s = String::from("Hello, World!");
183+
let t = String::from("foo, bar");
184+
s = t;
185+
}

tests/ui/collection_is_never_read.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,17 @@ error: collection is never read
4848
LL | let x = vec![1, 2, 3]; // WARNING
4949
| ^^^^^^^^^^^^^^^^^^^^^^
5050

51-
error: aborting due to 8 previous errors
51+
error: collection is never read
52+
--> $DIR/collection_is_never_read.rs:169:5
53+
|
54+
LL | let mut s = String::new();
55+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
56+
57+
error: collection is never read
58+
--> $DIR/collection_is_never_read.rs:182:5
59+
|
60+
LL | let mut s = String::from("Hello, World!");
61+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
62+
63+
error: aborting due to 10 previous errors
5264

0 commit comments

Comments
 (0)