about summary refs log tree commit diff
path: root/clippy_lints/src/methods/seek_from_current.rs
blob: d318462e58415ab6c3cac28984c8dd42b0e26cad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use rustc_ast::ast::{LitIntType, LitKind};
use rustc_data_structures::packed::Pu128;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::sym;

use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_enum_variant_ctor;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::implements_trait;

use super::SEEK_FROM_CURRENT;

pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
    let ty = cx.typeck_results().expr_ty(recv);

    if let Some(def_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) {
        if implements_trait(cx, ty, def_id, &[]) && arg_is_seek_from_current(cx, arg) {
            let mut applicability = Applicability::MachineApplicable;
            let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability);

            span_lint_and_sugg(
                cx,
                SEEK_FROM_CURRENT,
                expr.span,
                "using `SeekFrom::Current` to start from current position",
                "replace with",
                format!("{snip}.stream_position()"),
                applicability,
            );
        }
    }
}

fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
    if let ExprKind::Call(f, [arg]) = expr.kind
        && let ExprKind::Path(ref path) = f.kind
        && let Some(ctor_call_id) = cx.qpath_res(path, f.hir_id).opt_def_id()
        && is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Current), ctor_call_id)
    {
        // check if argument of `SeekFrom::Current` is `0`
        if let ExprKind::Lit(lit) = arg.kind
            && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node
        {
            return true;
        }
    }

    false
}