@@ -80,6 +80,45 @@ declare_clippy_lint! {
80
80
"using a binding which is prefixed with an underscore"
81
81
}
82
82
83
+ declare_clippy_lint ! {
84
+ /// ### What it does
85
+ /// Checks for the use of item with a single leading
86
+ /// underscore.
87
+ ///
88
+ /// ### Why is this bad?
89
+ /// A single leading underscore is usually used to indicate
90
+ /// that a item will not be used. Using such a item breaks this
91
+ /// expectation.
92
+ ///
93
+ /// ### Example
94
+ /// ```no_run
95
+ /// fn _foo() {}
96
+ ///
97
+ /// struct _FooStruct {}
98
+ ///
99
+ /// fn main() {
100
+ /// _foo();
101
+ /// let _ = _FooStruct{};
102
+ /// }
103
+ /// ```
104
+ ///
105
+ /// Use instead:
106
+ /// ```no_run
107
+ /// fn foo() {}
108
+ ///
109
+ /// struct FooStruct {}
110
+ ///
111
+ /// fn main() {
112
+ /// foo();
113
+ /// let _ = FooStruct{};
114
+ /// }
115
+ /// ```
116
+ #[ clippy:: version = "pre 1.29.0" ]
117
+ pub USED_UNDERSCORE_ITEMS ,
118
+ pedantic,
119
+ "using a item which is prefixed with an underscore"
120
+ }
121
+
83
122
declare_clippy_lint ! {
84
123
/// ### What it does
85
124
/// Checks for the use of short circuit boolean conditions as
@@ -104,6 +143,7 @@ declare_clippy_lint! {
104
143
declare_lint_pass ! ( LintPass => [
105
144
TOPLEVEL_REF_ARG ,
106
145
USED_UNDERSCORE_BINDING ,
146
+ USED_UNDERSCORE_ITEMS ,
107
147
SHORT_CIRCUIT_STATEMENT ,
108
148
] ) ;
109
149
@@ -205,51 +245,99 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
205
245
{
206
246
return ;
207
247
}
208
- let ( definition_hir_id, ident) = match expr. kind {
209
- ExprKind :: Path ( ref qpath) => {
210
- if let QPath :: Resolved ( None , path) = qpath
211
- && let Res :: Local ( id) = path. res
212
- && is_used ( cx, expr)
213
- {
214
- ( id, last_path_segment ( qpath) . ident )
215
- } else {
216
- return ;
217
- }
218
- } ,
219
- ExprKind :: Field ( recv, ident) => {
220
- if let Some ( adt_def) = cx. typeck_results ( ) . expr_ty_adjusted ( recv) . ty_adt_def ( )
221
- && let Some ( field) = adt_def. all_fields ( ) . find ( |field| field. name == ident. name )
222
- && let Some ( local_did) = field. did . as_local ( )
223
- && !cx. tcx . type_of ( field. did ) . skip_binder ( ) . is_phantom_data ( )
224
- {
225
- ( cx. tcx . local_def_id_to_hir_id ( local_did) , ident)
226
- } else {
227
- return ;
228
- }
248
+
249
+ used_underscore_binding ( cx, expr) ;
250
+ used_underscore_items ( cx, expr) ;
251
+ }
252
+ }
253
+
254
+ fn used_underscore_items < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
255
+ let ( def_id, ident) = match expr. kind {
256
+ ExprKind :: Call ( func, ..) => {
257
+ if let ExprKind :: Path ( QPath :: Resolved ( .., path) ) = func. kind
258
+ && let Some ( last_segment) = path. segments . last ( )
259
+ && let Res :: Def ( _, def_id) = last_segment. res
260
+ {
261
+ ( def_id, last_segment. ident )
262
+ } else {
263
+ return ;
264
+ }
265
+ } ,
266
+ ExprKind :: MethodCall ( path, ..) => {
267
+ if let Some ( def_id) = cx. typeck_results ( ) . type_dependent_def_id ( expr. hir_id ) {
268
+ ( def_id, path. ident )
269
+ } else {
270
+ return ;
271
+ }
272
+ } ,
273
+ ExprKind :: Struct ( QPath :: Resolved ( _, path) , ..) => {
274
+ if let Some ( last_segment) = path. segments . last ( )
275
+ && let Res :: Def ( _, def_id) = last_segment. res
276
+ {
277
+ ( def_id, last_segment. ident )
278
+ } else {
279
+ return ;
280
+ }
281
+ } ,
282
+ _ => return ,
283
+ } ;
284
+ let name = ident. name . as_str ( ) ;
285
+ let definition_span = cx. tcx . def_span ( def_id) ;
286
+ if name. starts_with ( '_' ) && !name. starts_with ( "__" ) && !definition_span. from_expansion ( ) {
287
+ span_lint_and_then (
288
+ cx,
289
+ USED_UNDERSCORE_ITEMS ,
290
+ expr. span ,
291
+ "used underscore-prefixed item" . to_string ( ) ,
292
+ |diag| {
293
+ diag. span_note ( definition_span, "item is defined here" . to_string ( ) ) ;
229
294
} ,
230
- _ => return ,
231
- } ;
295
+ ) ;
296
+ }
297
+ }
232
298
233
- let name = ident. name . as_str ( ) ;
234
- if name. starts_with ( '_' )
235
- && !name. starts_with ( "__" )
236
- && let definition_span = cx. tcx . hir ( ) . span ( definition_hir_id)
237
- && !definition_span. from_expansion ( )
238
- && !fulfill_or_allowed ( cx, USED_UNDERSCORE_BINDING , [ expr. hir_id , definition_hir_id] )
239
- {
240
- span_lint_and_then (
241
- cx,
242
- USED_UNDERSCORE_BINDING ,
243
- expr. span ,
244
- format ! (
245
- "used binding `{name}` which is prefixed with an underscore. A leading \
246
- underscore signals that a binding will not be used"
247
- ) ,
248
- |diag| {
249
- diag. span_note ( definition_span, format ! ( "`{name}` is defined here" ) ) ;
250
- } ,
251
- ) ;
252
- }
299
+ fn used_underscore_binding < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
300
+ let ( definition_hir_id, ident) = match expr. kind {
301
+ ExprKind :: Path ( ref qpath) => {
302
+ if let QPath :: Resolved ( None , path) = qpath
303
+ && let Res :: Local ( id) = path. res
304
+ && is_used ( cx, expr)
305
+ {
306
+ ( id, last_path_segment ( qpath) . ident )
307
+ } else {
308
+ return ;
309
+ }
310
+ } ,
311
+ ExprKind :: Field ( recv, ident) => {
312
+ if let Some ( adt_def) = cx. typeck_results ( ) . expr_ty_adjusted ( recv) . ty_adt_def ( )
313
+ && let Some ( field) = adt_def. all_fields ( ) . find ( |field| field. name == ident. name )
314
+ && let Some ( local_did) = field. did . as_local ( )
315
+ && !cx. tcx . type_of ( field. did ) . skip_binder ( ) . is_phantom_data ( )
316
+ {
317
+ ( cx. tcx . local_def_id_to_hir_id ( local_did) , ident)
318
+ } else {
319
+ return ;
320
+ }
321
+ } ,
322
+ _ => return ,
323
+ } ;
324
+
325
+ let name = ident. name . as_str ( ) ;
326
+ if name. starts_with ( '_' )
327
+ && !name. starts_with ( "__" )
328
+ && let definition_span = cx. tcx . hir ( ) . span ( definition_hir_id)
329
+ && !definition_span. from_expansion ( )
330
+ && !fulfill_or_allowed ( cx, USED_UNDERSCORE_BINDING , [ expr. hir_id , definition_hir_id] )
331
+ {
332
+ span_lint_and_then (
333
+ cx,
334
+ USED_UNDERSCORE_BINDING ,
335
+ expr. span ,
336
+ "used underscore-prefixed binding" . to_string ( ) ,
337
+ |diag| {
338
+ diag. span_note ( definition_span, "binding is defined here" . to_string ( ) ) ;
339
+ } ,
340
+ ) ;
253
341
}
254
342
}
255
343
0 commit comments