]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/unused_io_amount.rs
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / unused_io_amount.rs
CommitLineData
cdc7bbd5
XL
1use clippy_utils::diagnostics::span_lint;
2use clippy_utils::{is_try, match_trait_method, paths};
f20569fa
XL
3use rustc_hir as hir;
4use rustc_lint::{LateContext, LateLintPass};
5use rustc_session::{declare_lint_pass, declare_tool_lint};
6
7declare_clippy_lint! {
94222f64
XL
8 /// ### What it does
9 /// Checks for unused written/read amount.
f20569fa 10 ///
94222f64
XL
11 /// ### Why is this bad?
12 /// `io::Write::write(_vectored)` and
f20569fa
XL
13 /// `io::Read::read(_vectored)` are not guaranteed to
14 /// process the entire buffer. They return how many bytes were processed, which
15 /// might be smaller
16 /// than a given buffer's length. If you don't need to deal with
17 /// partial-write/read, use
18 /// `write_all`/`read_exact` instead.
19 ///
94222f64
XL
20 /// ### Known problems
21 /// Detects only common patterns.
f20569fa 22 ///
94222f64 23 /// ### Example
f20569fa
XL
24 /// ```rust,ignore
25 /// use std::io;
26 /// fn foo<W: io::Write>(w: &mut W) -> io::Result<()> {
27 /// // must be `w.write_all(b"foo")?;`
28 /// w.write(b"foo")?;
29 /// Ok(())
30 /// }
31 /// ```
32 pub UNUSED_IO_AMOUNT,
33 correctness,
34 "unused written/read amount"
35}
36
37declare_lint_pass!(UnusedIoAmount => [UNUSED_IO_AMOUNT]);
38
39impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
40 fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
41 let expr = match s.kind {
cdc7bbd5 42 hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
f20569fa
XL
43 _ => return,
44 };
45
46 match expr.kind {
cdc7bbd5
XL
47 hir::ExprKind::Match(res, _, _) if is_try(cx, expr).is_some() => {
48 if let hir::ExprKind::Call(func, args) = res.kind {
f20569fa
XL
49 if matches!(
50 func.kind,
17df50a5 51 hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, _))
f20569fa 52 ) {
cdc7bbd5 53 check_map_error(cx, &args[0], expr);
f20569fa
XL
54 }
55 } else {
cdc7bbd5 56 check_map_error(cx, res, expr);
f20569fa
XL
57 }
58 },
cdc7bbd5 59 hir::ExprKind::MethodCall(path, _, args, _) => match &*path.ident.as_str() {
f20569fa 60 "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => {
cdc7bbd5 61 check_map_error(cx, &args[0], expr);
f20569fa
XL
62 },
63 _ => (),
64 },
f20569fa
XL
65 _ => (),
66 }
67 }
68}
69
cdc7bbd5
XL
70fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
71 let mut call = call;
17df50a5 72 while let hir::ExprKind::MethodCall(path, _, args, _) = call.kind {
cdc7bbd5
XL
73 if matches!(&*path.ident.as_str(), "or" | "or_else" | "ok") {
74 call = &args[0];
75 } else {
76 break;
77 }
78 }
79 check_method_call(cx, call, expr);
80}
81
f20569fa 82fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
cdc7bbd5 83 if let hir::ExprKind::MethodCall(path, _, _, _) = call.kind {
f20569fa
XL
84 let symbol = &*path.ident.as_str();
85 let read_trait = match_trait_method(cx, call, &paths::IO_READ);
86 let write_trait = match_trait_method(cx, call, &paths::IO_WRITE);
87
88 match (read_trait, write_trait, symbol) {
89 (true, _, "read") => span_lint(
90 cx,
91 UNUSED_IO_AMOUNT,
92 expr.span,
93 "read amount is not handled. Use `Read::read_exact` instead",
94 ),
95 (true, _, "read_vectored") => span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "read amount is not handled"),
96 (_, true, "write") => span_lint(
97 cx,
98 UNUSED_IO_AMOUNT,
99 expr.span,
100 "written amount is not handled. Use `Write::write_all` instead",
101 ),
102 (_, true, "write_vectored") => span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "written amount is not handled"),
103 _ => (),
104 }
105 }
106}