blob: 63d41677feed2a09758dfec48a1b745c39bdb145 [file] [log] [blame]
use rustc_ast::ast::{LitIntType, LitKind};
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::source::snippet_with_applicability;
use clippy_utils::ty::implements_trait;
use clippy_utils::{match_def_path, paths};
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, args) = expr.kind
&& let ExprKind::Path(ref path) = f.kind
&& let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id()
&& match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT)
{
// check if argument of `SeekFrom::Current` is `0`
if args.len() == 1
&& let ExprKind::Lit(lit) = args[0].kind
&& let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
{
return true;
}
}
false
}