Skip to content

Commit 11c3cce

Browse files
committed
new lint
1 parent f58088b commit 11c3cce

File tree

7 files changed

+127
-0
lines changed

7 files changed

+127
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5367,6 +5367,7 @@ Released 2018-09-13
53675367
[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
53685368
[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
53695369
[`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
5370+
[`bufreader_stdin`]: https://rust-lang.github.io/rust-clippy/master/index.html#bufreader_stdin
53705371
[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
53715372
[`byte_char_slices`]: https://rust-lang.github.io/rust-clippy/master/index.html#byte_char_slices
53725373
[`bytes_count_to_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_count_to_len
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::match_def_path;
3+
use clippy_utils::source::snippet;
4+
use rustc_errors::Applicability;
5+
use rustc_hir::{ExprKind, QPath, TyKind};
6+
use rustc_lint::{LateContext, LateLintPass};
7+
use rustc_session::declare_lint_pass;
8+
use rustc_span::sym;
9+
10+
declare_clippy_lint! {
11+
/// ### What it does
12+
/// Checks for usage of `BufReader::new` with `Stdin` or `StdinLock`.
13+
///
14+
/// ### Why is this bad?
15+
/// `Stdin` is already buffered. Re-buffering it only increase the memcpy calls.
16+
///
17+
/// ### Example
18+
/// ```no_run
19+
/// let reader = std::io::BufReader::new(std::io::stdin());
20+
/// ```
21+
/// Use instead:
22+
/// ```no_run
23+
/// let stdin = std::io::stdin();
24+
/// let reader = stdin.lock();
25+
/// ```
26+
#[clippy::version = "1.84.0"]
27+
pub BUFREADER_STDIN,
28+
perf,
29+
"using `BufReader::new` with `Stdin` or `StdinLock` is unnecessary and less efficient"
30+
}
31+
32+
declare_lint_pass!(BufreaderStdinlock => [BUFREADER_STDIN]);
33+
34+
impl<'tcx> LateLintPass<'tcx> for BufreaderStdinlock {
35+
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
36+
if e.span.from_expansion() {
37+
return;
38+
}
39+
if let ExprKind::Call(func, [arg]) = e.kind
40+
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = func.kind
41+
&& seg.ident.name == sym::new
42+
&& let TyKind::Path(ref qpath) = ty.kind
43+
&& let Some(did) = cx.qpath_res(qpath, ty.hir_id).opt_def_id()
44+
&& match_def_path(cx, did, &["std", "io", "buffered", "bufreader", "BufReader"])
45+
&& let arg_ty = cx.typeck_results().expr_ty(arg)
46+
&& let Some(arg_did) = arg_ty.ty_adt_def().map(|def| def.did())
47+
{
48+
if match_def_path(cx, arg_did, &["std", "io", "stdio", "Stdin"]) {
49+
span_lint_and_sugg(
50+
cx,
51+
&BUFREADER_STDIN,
52+
e.span,
53+
"using `BufReader::new` with `Stdin`",
54+
"instead of wrapping `Stdin` in `BufReader`, use the `lock` method directly",
55+
format!("{}.lock()", snippet(cx, arg.span, "..")),
56+
Applicability::MachineApplicable,
57+
);
58+
} else if match_def_path(cx, arg_did, &["std", "io", "stdio", "StdinLock"]) {
59+
span_lint_and_sugg(
60+
cx,
61+
&BUFREADER_STDIN,
62+
e.span,
63+
"using `BufReader::new` with `Stdin`",
64+
"instead of wrapping `StdinLock` in `BufReader`, use it self",
65+
snippet(cx, arg.span, "..").to_string(),
66+
Applicability::MachineApplicable,
67+
);
68+
} else {
69+
return;
70+
};
71+
}
72+
}
73+
}

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
6868
crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO,
6969
crate::borrow_deref_ref::BORROW_DEREF_REF_INFO,
7070
crate::box_default::BOX_DEFAULT_INFO,
71+
crate::bufreader_stdin::BUFREADER_STDIN_INFO,
7172
crate::byte_char_slices::BYTE_CHAR_SLICES_INFO,
7273
crate::cargo::CARGO_COMMON_METADATA_INFO,
7374
crate::cargo::LINT_GROUPS_PRIORITY_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ mod bool_to_int_with_if;
8989
mod booleans;
9090
mod borrow_deref_ref;
9191
mod box_default;
92+
mod bufreader_stdin;
9293
mod byte_char_slices;
9394
mod cargo;
9495
mod casts;
@@ -963,5 +964,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
963964
store.register_late_pass(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp));
964965
store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
965966
store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
967+
store.register_late_pass(|_| Box::new(bufreader_stdin::BufreaderStdinlock));
966968
// add lints here, do not remove this comment, it's used in `new_lint`
967969
}

tests/ui/bufreader_stdin.fixed

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![warn(clippy::bufreader_stdin)]
2+
use std::io::{self, BufReader};
3+
4+
fn main() {
5+
let a = io::stdin();
6+
let reader = a.lock();
7+
8+
let b = io::stdin().lock();
9+
let reader = b;
10+
}

tests/ui/bufreader_stdin.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![warn(clippy::BUFREADER_STDIN)]
2+
use std::io::{self, BufReader};
3+
4+
fn main() {
5+
let a = io::stdin();
6+
let reader = BufReader::new(a);
7+
8+
let b = io::stdin().lock();
9+
let reader = BufReader::new(b);
10+
}

tests/ui/bufreader_stdin.stderr

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error: unknown lint: `clippy::BUFREADER_STDIN`
2+
--> tests/ui/bufreader_stdin.rs:1:9
3+
|
4+
LL | #![warn(clippy::BUFREADER_STDIN)]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::bufreader_stdin`
6+
|
7+
= note: `-D unknown-lints` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(unknown_lints)]`
9+
10+
error: using `BufReader::new` with `Stdin`
11+
--> tests/ui/bufreader_stdin.rs:6:18
12+
|
13+
LL | let reader = BufReader::new(a);
14+
| ^^^^^^^^^^^^^^^^^
15+
|
16+
= note: `-D clippy::bufreader-stdin` implied by `-D warnings`
17+
= help: to override `-D warnings` add `#[allow(clippy::bufreader_stdin)]`
18+
help: instead of wrapping `Stdin` in `BufReader`, use the `lock` method directly
19+
|
20+
LL | let reader = a.lock();
21+
| ~~~~~~~~
22+
23+
error: using `BufReader::new` with `Stdin`
24+
--> tests/ui/bufreader_stdin.rs:9:18
25+
|
26+
LL | let reader = BufReader::new(b);
27+
| ^^^^^^^^^^^^^^^^^ help: instead of wrapping `StdinLock` in `BufReader`, use it self: `b`
28+
29+
error: aborting due to 3 previous errors
30+

0 commit comments

Comments
 (0)