11use clippy_utils:: diagnostics:: { span_lint_hir, span_lint_hir_and_then} ;
2+ use clippy_utils:: is_lint_allowed;
23use clippy_utils:: source:: snippet_opt;
34use clippy_utils:: ty:: has_drop;
45use rustc_errors:: Applicability ;
56use rustc_hir:: def:: { DefKind , Res } ;
6- use rustc_hir:: { is_range_literal, BinOpKind , BlockCheckMode , Expr , ExprKind , Stmt , StmtKind , UnsafeSource } ;
7+ use rustc_hir:: { is_range_literal, BinOpKind , BlockCheckMode , Expr , ExprKind , PatKind , Stmt , StmtKind , UnsafeSource } ;
78use rustc_lint:: { LateContext , LateLintPass } ;
89use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
910use std:: ops:: Deref ;
@@ -13,7 +14,7 @@ declare_clippy_lint! {
1314 /// Checks for statements which have no effect.
1415 ///
1516 /// ### Why is this bad?
16- /// Similar to dead code, these statements are actually
17+ /// Unlike dead code, these statements are actually
1718 /// executed. However, as they have no effect, all they do is make the code less
1819 /// readable.
1920 ///
@@ -26,6 +27,28 @@ declare_clippy_lint! {
2627 "statements with no effect"
2728}
2829
30+ declare_clippy_lint ! {
31+ /// ### What it does
32+ /// Checks for binding to underscore prefixed variable without side-effects.
33+ ///
34+ /// ### Why is this bad?
35+ /// Unlike dead code, these bindings are actually
36+ /// executed. However, as they have no effect and shouldn't be used further on, all they
37+ /// do is make the code less readable.
38+ ///
39+ /// ### Known problems
40+ /// Further usage of this variable is not checked, which can lead to false positives if it is
41+ /// used later in the code.
42+ ///
43+ /// ### Example
44+ /// ```rust,ignore
45+ /// let _i_serve_no_purpose = 1;
46+ /// ```
47+ pub NO_EFFECT_UNDERSCORE_BINDING ,
48+ pedantic,
49+ "binding to `_` prefixed variable with no side-effect"
50+ }
51+
2952declare_clippy_lint ! {
3053 /// ### What it does
3154 /// Checks for expression statements that can be reduced to a
@@ -44,6 +67,46 @@ declare_clippy_lint! {
4467 "outer expressions with no effect"
4568}
4669
70+ declare_lint_pass ! ( NoEffect => [ NO_EFFECT , UNNECESSARY_OPERATION , NO_EFFECT_UNDERSCORE_BINDING ] ) ;
71+
72+ impl < ' tcx > LateLintPass < ' tcx > for NoEffect {
73+ fn check_stmt ( & mut self , cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) {
74+ if check_no_effect ( cx, stmt) {
75+ return ;
76+ }
77+ check_unnecessary_operation ( cx, stmt) ;
78+ }
79+ }
80+
81+ fn check_no_effect ( cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) -> bool {
82+ if let StmtKind :: Semi ( expr) = stmt. kind {
83+ if has_no_effect ( cx, expr) {
84+ span_lint_hir ( cx, NO_EFFECT , expr. hir_id , stmt. span , "statement with no effect" ) ;
85+ return true ;
86+ }
87+ } else if let StmtKind :: Local ( local) = stmt. kind {
88+ if_chain ! {
89+ if !is_lint_allowed( cx, NO_EFFECT_UNDERSCORE_BINDING , local. hir_id) ;
90+ if let Some ( init) = local. init;
91+ if !local. pat. span. from_expansion( ) ;
92+ if has_no_effect( cx, init) ;
93+ if let PatKind :: Binding ( _, _, ident, _) = local. pat. kind;
94+ if ident. name. to_ident_string( ) . starts_with( '_' ) ;
95+ then {
96+ span_lint_hir(
97+ cx,
98+ NO_EFFECT_UNDERSCORE_BINDING ,
99+ init. hir_id,
100+ stmt. span,
101+ "binding to `_` prefixed variable with no side-effect"
102+ ) ;
103+ return true ;
104+ }
105+ }
106+ }
107+ false
108+ }
109+
47110fn has_no_effect ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
48111 if expr. span . from_expansion ( ) {
49112 return false ;
@@ -88,71 +151,59 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
88151 }
89152}
90153
91- declare_lint_pass ! ( NoEffect => [ NO_EFFECT , UNNECESSARY_OPERATION ] ) ;
92-
93- impl < ' tcx > LateLintPass < ' tcx > for NoEffect {
94- fn check_stmt ( & mut self , cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) {
95- if let StmtKind :: Semi ( expr) = stmt. kind {
96- if has_no_effect ( cx, expr) {
97- span_lint_hir ( cx, NO_EFFECT , expr. hir_id , stmt. span , "statement with no effect" ) ;
98- } else if let Some ( reduced) = reduce_expression ( cx, expr) {
99- for e in & reduced {
100- if e. span . from_expansion ( ) {
101- return ;
102- }
103- }
104- if let ExprKind :: Index ( ..) = & expr. kind {
105- let snippet;
106- if_chain ! {
107- if let Some ( arr) = snippet_opt( cx, reduced[ 0 ] . span) ;
108- if let Some ( func) = snippet_opt( cx, reduced[ 1 ] . span) ;
109- then {
110- snippet = format!( "assert!({}.len() > {});" , & arr, & func) ;
111- } else {
112- return ;
113- }
114- }
115- span_lint_hir_and_then (
116- cx,
117- UNNECESSARY_OPERATION ,
118- expr. hir_id ,
119- stmt. span ,
120- "unnecessary operation" ,
121- |diag| {
122- diag. span_suggestion (
123- stmt. span ,
124- "statement can be written as" ,
125- snippet,
126- Applicability :: MaybeIncorrect ,
127- ) ;
128- } ,
129- ) ;
154+ fn check_unnecessary_operation ( cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) {
155+ if_chain ! {
156+ if let StmtKind :: Semi ( expr) = stmt. kind;
157+ if let Some ( reduced) = reduce_expression( cx, expr) ;
158+ if !& reduced. iter( ) . any( |e| e. span. from_expansion( ) ) ;
159+ then {
160+ if let ExprKind :: Index ( ..) = & expr. kind {
161+ let snippet;
162+ if let ( Some ( arr) , Some ( func) ) = ( snippet_opt( cx, reduced[ 0 ] . span) , snippet_opt( cx, reduced[ 1 ] . span) ) {
163+ snippet = format!( "assert!({}.len() > {});" , & arr, & func) ;
130164 } else {
131- let mut snippet = String :: new ( ) ;
132- for e in reduced {
133- if let Some ( snip) = snippet_opt ( cx, e. span ) {
134- snippet. push_str ( & snip) ;
135- snippet. push ( ';' ) ;
136- } else {
137- return ;
138- }
165+ return ;
166+ }
167+ span_lint_hir_and_then(
168+ cx,
169+ UNNECESSARY_OPERATION ,
170+ expr. hir_id,
171+ stmt. span,
172+ "unnecessary operation" ,
173+ |diag| {
174+ diag. span_suggestion(
175+ stmt. span,
176+ "statement can be written as" ,
177+ snippet,
178+ Applicability :: MaybeIncorrect ,
179+ ) ;
180+ } ,
181+ ) ;
182+ } else {
183+ let mut snippet = String :: new( ) ;
184+ for e in reduced {
185+ if let Some ( snip) = snippet_opt( cx, e. span) {
186+ snippet. push_str( & snip) ;
187+ snippet. push( ';' ) ;
188+ } else {
189+ return ;
139190 }
140- span_lint_hir_and_then (
141- cx,
142- UNNECESSARY_OPERATION ,
143- expr. hir_id ,
144- stmt. span ,
145- "unnecessary operation" ,
146- |diag| {
147- diag. span_suggestion (
148- stmt. span ,
149- "statement can be reduced to" ,
150- snippet,
151- Applicability :: MachineApplicable ,
152- ) ;
153- } ,
154- ) ;
155191 }
192+ span_lint_hir_and_then(
193+ cx,
194+ UNNECESSARY_OPERATION ,
195+ expr. hir_id,
196+ stmt. span,
197+ "unnecessary operation" ,
198+ |diag| {
199+ diag. span_suggestion(
200+ stmt. span,
201+ "statement can be reduced to" ,
202+ snippet,
203+ Applicability :: MachineApplicable ,
204+ ) ;
205+ } ,
206+ ) ;
156207 }
157208 }
158209 }
0 commit comments