Skip to content

Commit 8279a00

Browse files
committed
[read_line_without_trim]: catch string eq checks
1 parent 9058b04 commit 8279a00

File tree

1 file changed

+55
-25
lines changed

1 file changed

+55
-25
lines changed

clippy_lints/src/methods/read_line_without_trim.rs

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use clippy_utils::{
44
diagnostics::span_lint_and_then, get_parent_expr, match_def_path, source::snippet, ty::is_type_diagnostic_item,
55
visitors::for_each_local_use_after_expr,
66
};
7+
use rustc_ast::LitKind;
78
use rustc_errors::Applicability;
9+
use rustc_hir::BinOpKind;
810
use rustc_hir::Expr;
911
use rustc_hir::QPath;
1012
use rustc_hir::{def::Res, ExprKind};
@@ -31,33 +33,61 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
3133
// parsed into a type that will always fail if it has a trailing newline.
3234
for_each_local_use_after_expr(cx, local_id, call.hir_id, |expr| {
3335
if let Some(parent) = get_parent_expr(cx, expr)
34-
&& let ExprKind::MethodCall(segment, .., span) = parent.kind
35-
&& segment.ident.name == sym!(parse)
36-
&& let parse_result_ty = cx.typeck_results().expr_ty(parent)
37-
&& is_type_diagnostic_item(cx, parse_result_ty, sym::Result)
38-
&& let ty::Adt(_, substs) = parse_result_ty.kind()
39-
&& let Some(ok_ty) = substs[0].as_type()
40-
&& parse_fails_on_trailing_newline(ok_ty)
4136
{
42-
let local_snippet = snippet(cx, expr.span, "<expr>");
43-
span_lint_and_then(
44-
cx,
45-
READ_LINE_WITHOUT_TRIM,
46-
span,
47-
"calling `.parse()` without trimming the trailing newline character",
48-
|diag| {
49-
diag.span_note(call.span, "call to `.read_line()` here, \
50-
which leaves a trailing newline character in the buffer, \
51-
which in turn will cause `.parse()` to fail");
37+
if let ExprKind::MethodCall(segment, .., span) = parent.kind
38+
&& segment.ident.name == sym!(parse)
39+
&& let parse_result_ty = cx.typeck_results().expr_ty(parent)
40+
&& is_type_diagnostic_item(cx, parse_result_ty, sym::Result)
41+
&& let ty::Adt(_, substs) = parse_result_ty.kind()
42+
&& let Some(ok_ty) = substs[0].as_type()
43+
&& parse_fails_on_trailing_newline(ok_ty)
44+
{
45+
let local_snippet: std::borrow::Cow<'_, str> = snippet(cx, expr.span, "<expr>");
46+
span_lint_and_then(
47+
cx,
48+
READ_LINE_WITHOUT_TRIM,
49+
span,
50+
"calling `.parse()` without trimming the trailing newline character",
51+
|diag| {
52+
diag.span_note(call.span, "call to `.read_line()` here, \
53+
which leaves a trailing newline character in the buffer, \
54+
which in turn will cause `.parse()` to fail");
5255

53-
diag.span_suggestion(
54-
expr.span,
55-
"try",
56-
format!("{local_snippet}.trim_end()"),
57-
Applicability::MachineApplicable,
58-
);
59-
}
60-
);
56+
diag.span_suggestion(
57+
expr.span,
58+
"try",
59+
format!("{local_snippet}.trim_end()"),
60+
Applicability::MachineApplicable,
61+
);
62+
}
63+
);
64+
} else if let ExprKind::Binary(binop, left, right) = parent.kind
65+
&& let BinOpKind::Eq = binop.node
66+
&& let ExprKind::Lit(lit) = right.kind
67+
&& let LitKind::Str(sym, _) = lit.node
68+
&& !sym.as_str().ends_with('\n')
69+
{
70+
span_lint_and_then(
71+
cx,
72+
READ_LINE_WITHOUT_TRIM,
73+
parent.span,
74+
"comparing a string literal without trimming the trailing newline character",
75+
|diag| {
76+
let local_snippet: std::borrow::Cow<'_, str> = snippet(cx, expr.span, "<expr>");
77+
78+
diag.span_note(call.span, "call to `.read_line()` here, \
79+
which leaves a trailing newline character in the buffer, \
80+
which in turn will cause the comparison to always fail");
81+
82+
diag.span_suggestion(
83+
expr.span,
84+
"try",
85+
format!("{local_snippet}.trim_end()"),
86+
Applicability::MachineApplicable,
87+
);
88+
}
89+
);
90+
}
6191
}
6292

6393
// only consider the first use to prevent this scenario:

0 commit comments

Comments
 (0)