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