@@ -5,9 +5,10 @@ use clippy_utils::source::snippet;
5
5
use clippy_utils:: ty:: is_type_diagnostic_item;
6
6
use clippy_utils:: visitors:: for_each_local_use_after_expr;
7
7
use clippy_utils:: { get_parent_expr, match_def_path} ;
8
+ use rustc_ast:: LitKind ;
8
9
use rustc_errors:: Applicability ;
9
10
use rustc_hir:: def:: Res ;
10
- use rustc_hir:: { Expr , ExprKind , QPath } ;
11
+ use rustc_hir:: { BinOpKind , Expr , ExprKind , QPath } ;
11
12
use rustc_lint:: LateContext ;
12
13
use rustc_middle:: ty:: { self , Ty } ;
13
14
use rustc_span:: sym;
@@ -30,37 +31,67 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
30
31
// now let's check if the first use of the string passed to `::read_line()` is
31
32
// parsed into a type that will always fail if it has a trailing newline.
32
33
for_each_local_use_after_expr ( cx, local_id, call. hir_id , |expr| {
33
- 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 ( _, args ) = parse_result_ty. kind ( )
39
- && let Some ( ok_ty) = args [ 0 ] . as_type ( )
40
- && parse_fails_on_trailing_newline ( ok_ty)
41
- {
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 (
50
- call. span ,
51
- "call to `.read_line()` here, \
52
- which leaves a trailing newline character in the buffer, \
53
- which in turn will cause `.parse()` to fail",
54
- ) ;
34
+ if let Some ( parent) = get_parent_expr ( cx, expr) {
35
+ if let ExprKind :: MethodCall ( segment, .., span) = parent. kind
36
+ && segment. ident . name == sym ! ( parse)
37
+ && let parse_result_ty = cx. typeck_results ( ) . expr_ty ( parent)
38
+ && is_type_diagnostic_item ( cx, parse_result_ty, sym:: Result )
39
+ && let ty:: Adt ( _, substs ) = parse_result_ty. kind ( )
40
+ && let Some ( ok_ty) = substs [ 0 ] . as_type ( )
41
+ && parse_fails_on_trailing_newline ( ok_ty)
42
+ {
43
+ let local_snippet: std :: borrow :: Cow < ' _ , str > = snippet ( cx, expr. span , "<expr>" ) ;
44
+ span_lint_and_then (
45
+ cx,
46
+ READ_LINE_WITHOUT_TRIM ,
47
+ span,
48
+ "calling `.parse()` without trimming the trailing newline character" ,
49
+ |diag| {
50
+ diag. span_note (
51
+ call. span ,
52
+ "call to `.read_line()` here, \
53
+ which leaves a trailing newline character in the buffer, \
54
+ which in turn will cause `.parse()` to fail",
55
+ ) ;
55
56
56
- diag. span_suggestion (
57
- expr. span ,
58
- "try" ,
59
- format ! ( "{local_snippet}.trim_end()" ) ,
60
- Applicability :: MachineApplicable ,
61
- ) ;
62
- } ,
63
- ) ;
57
+ diag. span_suggestion (
58
+ expr. span ,
59
+ "try" ,
60
+ format ! ( "{local_snippet}.trim_end()" ) ,
61
+ Applicability :: MachineApplicable ,
62
+ ) ;
63
+ } ,
64
+ ) ;
65
+ } else if let ExprKind :: Binary ( binop, _, right) = parent. kind
66
+ && let BinOpKind :: Eq = binop. node
67
+ && let ExprKind :: Lit ( lit) = right. kind
68
+ && let LitKind :: Str ( sym, _) = lit. node
69
+ && !sym. as_str ( ) . ends_with ( '\n' )
70
+ {
71
+ span_lint_and_then (
72
+ cx,
73
+ READ_LINE_WITHOUT_TRIM ,
74
+ parent. span ,
75
+ "comparing a string literal without trimming the trailing newline character" ,
76
+ |diag| {
77
+ let local_snippet = snippet ( cx, expr. span , "<expr>" ) ;
78
+
79
+ diag. span_note (
80
+ call. span ,
81
+ "call to `.read_line()` here, \
82
+ which leaves a trailing newline character in the buffer, \
83
+ which in turn will cause the comparison to always fail",
84
+ ) ;
85
+
86
+ diag. span_suggestion (
87
+ expr. span ,
88
+ "try" ,
89
+ format ! ( "{local_snippet}.trim_end()" ) ,
90
+ Applicability :: MachineApplicable ,
91
+ ) ;
92
+ } ,
93
+ ) ;
94
+ }
64
95
}
65
96
66
97
// only consider the first use to prevent this scenario:
0 commit comments