7
7
//! The module transforms all lint names to ascii lowercase to ensure that we don't have mismatches
8
8
//! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
9
9
//! a simple mistake)
10
- //!
11
- //! The metadata currently contains:
12
- //! - [x] TODO The lint declaration line for [#1303](https://github.com/rust-lang/rust-clippy/issues/1303)
13
- //! and [#6492](https://github.com/rust-lang/rust-clippy/issues/6492)
14
- //! - [ ] TODO The Applicability for each lint for [#4310](https://github.com/rust-lang/rust-clippy/issues/4310)
15
-
16
- // # Applicability
17
- // - TODO xFrednet 2021-01-17: Find lint emit and collect applicability
18
- // - TODO xFrednet 2021-02-28: 4x weird emission forwarding
19
- // - See clippy_lints/src/enum_variants.rs@EnumVariantNames::check_name
20
- // - TODO xFrednet 2021-02-28: 6x emission forwarding with local that is initializes from
21
- // function.
22
- // - See clippy_lints/src/methods/mod.rs@lint_binary_expr_with_method_call
23
- // - TODO xFrednet 2021-02-28: 2x lint from local from function call
24
- // - See clippy_lints/src/misc.rs@check_binary
25
- // - TODO xFrednet 2021-02-28: 2x lint from local from method call
26
- // - See clippy_lints/src/non_copy_const.rs@lint
10
+
27
11
// # NITs
28
12
// - TODO xFrednet 2021-02-13: Collect depreciations and maybe renames
29
13
30
14
use if_chain:: if_chain;
31
15
use rustc_data_structures:: fx:: FxHashMap ;
32
- use rustc_hir:: { self as hir, intravisit, intravisit:: Visitor , ExprKind , Item , ItemKind , Mutability , QPath , def:: DefKind } ;
16
+ use rustc_hir:: {
17
+ self as hir, def:: DefKind , intravisit, intravisit:: Visitor , ExprKind , Item , ItemKind , Mutability , QPath ,
18
+ } ;
33
19
use rustc_lint:: { CheckLintNameResult , LateContext , LateLintPass , LintContext , LintId } ;
34
20
use rustc_middle:: hir:: map:: Map ;
35
21
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
36
22
use rustc_span:: { sym, Loc , Span , Symbol } ;
37
- use serde:: Serialize ;
23
+ use serde:: { ser:: SerializeStruct , Serialize , Serializer } ;
24
+ use std:: collections:: BinaryHeap ;
38
25
use std:: fs:: { self , OpenOptions } ;
39
26
use std:: io:: prelude:: * ;
40
27
use std:: path:: Path ;
@@ -47,7 +34,7 @@ use crate::utils::{
47
34
/// This is the output file of the lint collector.
48
35
const OUTPUT_FILE : & str = "../metadata_collection.json" ;
49
36
/// These lints are excluded from the export.
50
- const BLACK_LISTED_LINTS : [ & str ; 2 ] = [ "lint_author" , "deep_code_inspection" ] ;
37
+ const BLACK_LISTED_LINTS : [ & str ; 3 ] = [ "lint_author" , "deep_code_inspection" , "internal_metadata_collector "] ;
51
38
/// These groups will be ignored by the lint group matcher. This is useful for collections like
52
39
/// `clippy::all`
53
40
const IGNORED_LINT_GROUPS : [ & str ; 1 ] = [ "clippy::all" ] ;
@@ -107,7 +94,7 @@ declare_clippy_lint! {
107
94
/// }
108
95
/// ```
109
96
pub INTERNAL_METADATA_COLLECTOR ,
110
- internal ,
97
+ internal_warn ,
111
98
"A busy bee collection metadata about lints"
112
99
}
113
100
@@ -116,22 +103,28 @@ impl_lint_pass!(MetadataCollector => [INTERNAL_METADATA_COLLECTOR]);
116
103
#[ allow( clippy:: module_name_repetitions) ]
117
104
#[ derive( Debug , Clone , Default ) ]
118
105
pub struct MetadataCollector {
119
- lints : Vec < LintMetadata > ,
106
+ /// All collected lints
107
+ ///
108
+ /// We use a Heap here to have the lints added in alphabetic order in the export
109
+ lints : BinaryHeap < LintMetadata > ,
120
110
applicability_into : FxHashMap < String , ApplicabilityInfo > ,
121
111
}
122
112
123
113
impl Drop for MetadataCollector {
124
114
/// You might ask: How hacky is this?
125
115
/// My answer: YES
126
116
fn drop ( & mut self ) {
117
+ // The metadata collector gets dropped twice, this makes sure that we only write
118
+ // when the list is full
127
119
if self . lints . is_empty ( ) {
128
120
return ;
129
121
}
130
122
131
123
let mut applicability_info = std:: mem:: take ( & mut self . applicability_into ) ;
132
124
133
125
// Mapping the final data
134
- self . lints
126
+ let mut lints = std:: mem:: take ( & mut self . lints ) . into_sorted_vec ( ) ;
127
+ lints
135
128
. iter_mut ( )
136
129
. for_each ( |x| x. applicability = applicability_info. remove ( & x. id ) ) ;
137
130
@@ -140,11 +133,11 @@ impl Drop for MetadataCollector {
140
133
fs:: remove_file ( OUTPUT_FILE ) . unwrap ( ) ;
141
134
}
142
135
let mut file = OpenOptions :: new ( ) . write ( true ) . create ( true ) . open ( OUTPUT_FILE ) . unwrap ( ) ;
143
- writeln ! ( file, "{}" , serde_json:: to_string_pretty( & self . lints) . unwrap( ) ) . unwrap ( ) ;
136
+ writeln ! ( file, "{}" , serde_json:: to_string_pretty( & lints) . unwrap( ) ) . unwrap ( ) ;
144
137
}
145
138
}
146
139
147
- #[ derive( Debug , Clone , Serialize ) ]
140
+ #[ derive( Debug , Clone , Serialize , PartialEq , Eq , PartialOrd , Ord ) ]
148
141
struct LintMetadata {
149
142
id : String ,
150
143
id_span : SerializableSpan ,
@@ -155,6 +148,24 @@ struct LintMetadata {
155
148
applicability : Option < ApplicabilityInfo > ,
156
149
}
157
150
151
+ // impl Ord for LintMetadata {
152
+ // fn cmp(&self, other: &Self) -> Ordering {
153
+ // self.id.cmp(&other.id)
154
+ // }
155
+ // }
156
+ //
157
+ // impl PartialOrd for LintMetadata {
158
+ // fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
159
+ // Some(self.cmp(other))
160
+ // }
161
+ // }
162
+ //
163
+ // impl PartialEq for LintMetadata {
164
+ // fn eq(&self, other: &Self) -> bool {
165
+ // self.id == other.id
166
+ // }
167
+ // }
168
+
158
169
impl LintMetadata {
159
170
fn new ( id : String , id_span : SerializableSpan , group : String , docs : String ) -> Self {
160
171
Self {
@@ -167,7 +178,7 @@ impl LintMetadata {
167
178
}
168
179
}
169
180
170
- #[ derive( Debug , Clone , Serialize ) ]
181
+ #[ derive( Debug , Clone , Serialize , PartialEq , Eq , PartialOrd , Ord ) ]
171
182
struct SerializableSpan {
172
183
path : String ,
173
184
line : usize ,
@@ -194,25 +205,30 @@ impl SerializableSpan {
194
205
}
195
206
}
196
207
197
- #[ derive( Debug , Clone , Default , Serialize ) ]
208
+ #[ derive( Debug , Clone , Default , PartialEq , Eq , PartialOrd , Ord ) ]
198
209
struct ApplicabilityInfo {
199
210
/// Indicates if any of the lint emissions uses multiple spans. This is related to
200
211
/// [rustfix#141](https://github.com/rust-lang/rustfix/issues/141) as such suggestions can
201
212
/// currently not be applied automatically.
202
- is_multi_suggestion : bool ,
203
- applicability : Option < String > ,
204
- }
205
-
206
- #[ allow( dead_code) ]
207
- fn log_to_file ( msg : & str ) {
208
- let mut file = OpenOptions :: new ( )
209
- . write ( true )
210
- . append ( true )
211
- . create ( true )
212
- . open ( "metadata-lint.log" )
213
- . unwrap ( ) ;
214
-
215
- write ! ( file, "{}" , msg) . unwrap ( ) ;
213
+ is_multi_part_suggestion : bool ,
214
+ applicability : Option < usize > ,
215
+ }
216
+
217
+ impl Serialize for ApplicabilityInfo {
218
+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
219
+ where
220
+ S : Serializer ,
221
+ {
222
+ let index = self . applicability . unwrap_or_default ( ) ;
223
+
224
+ let mut s = serializer. serialize_struct ( "ApplicabilityInfo" , 2 ) ?;
225
+ s. serialize_field ( "is_multi_part_suggestion" , & self . is_multi_part_suggestion ) ?;
226
+ s. serialize_field (
227
+ "applicability" ,
228
+ & paths:: APPLICABILITY_VALUES [ index] [ APPLICABILITY_NAME_INDEX ] ,
229
+ ) ?;
230
+ s. end ( )
231
+ }
216
232
}
217
233
218
234
impl < ' hir > LateLintPass < ' hir > for MetadataCollector {
@@ -266,16 +282,20 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
266
282
/// ```
267
283
fn check_expr ( & mut self , cx : & LateContext < ' hir > , expr : & ' hir hir:: Expr < ' _ > ) {
268
284
if let Some ( args) = match_lint_emission ( cx, expr) {
269
- let mut emission_info = extract_complex_emission_info ( cx, args) ;
285
+ let mut emission_info = extract_emission_info ( cx, args) ;
270
286
if emission_info. is_empty ( ) {
271
- lint_collection_error_span ( cx, expr. span , "Look, here ... I have no clue what todo with it" ) ;
287
+ // See:
288
+ // - src/misc.rs:734:9
289
+ // - src/methods/mod.rs:3545:13
290
+ // - src/methods/mod.rs:3496:13
291
+ // We are basically unable to resolve the lint name it self.
272
292
return ;
273
293
}
274
294
275
295
for ( lint_name, applicability, is_multi_part) in emission_info. drain ( ..) {
276
296
let app_info = self . applicability_into . entry ( lint_name) . or_default ( ) ;
277
297
app_info. applicability = applicability;
278
- app_info. is_multi_suggestion = is_multi_part;
298
+ app_info. is_multi_part_suggestion = is_multi_part;
279
299
}
280
300
}
281
301
}
@@ -289,7 +309,7 @@ fn sym_to_string(sym: Symbol) -> String {
289
309
}
290
310
291
311
fn extract_attr_docs_or_lint ( cx : & LateContext < ' _ > , item : & Item < ' _ > ) -> Option < String > {
292
- extract_attr_docs ( item) . or_else ( || {
312
+ extract_attr_docs ( cx , item) . or_else ( || {
293
313
lint_collection_error_item ( cx, item, "could not collect the lint documentation" ) ;
294
314
None
295
315
} )
@@ -305,8 +325,10 @@ fn extract_attr_docs_or_lint(cx: &LateContext<'_>, item: &Item<'_>) -> Option<St
305
325
/// ```
306
326
///
307
327
/// Would result in `Hello world!\n=^.^=\n`
308
- fn extract_attr_docs ( item : & Item < ' _ > ) -> Option < String > {
309
- item. attrs
328
+ fn extract_attr_docs ( cx : & LateContext < ' _ > , item : & Item < ' _ > ) -> Option < String > {
329
+ cx. tcx
330
+ . hir ( )
331
+ . attrs ( item. hir_id ( ) )
310
332
. iter ( )
311
333
. filter_map ( |ref x| x. doc_str ( ) . map ( |sym| sym. as_str ( ) . to_string ( ) ) )
312
334
. reduce ( |mut acc, sym| {
@@ -357,15 +379,6 @@ fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &s
357
379
) ;
358
380
}
359
381
360
- fn lint_collection_error_span ( cx : & LateContext < ' _ > , span : Span , message : & str ) {
361
- span_lint (
362
- cx,
363
- INTERNAL_METADATA_COLLECTOR ,
364
- span,
365
- & format ! ( "Metadata collection error: {}" , message) ,
366
- ) ;
367
- }
368
-
369
382
// ==================================================================
370
383
// Applicability
371
384
// ==================================================================
@@ -377,11 +390,15 @@ fn match_lint_emission<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>)
377
390
. find_map ( |emission_fn| match_function_call ( cx, expr, emission_fn) )
378
391
}
379
392
380
- fn extract_complex_emission_info < ' hir > (
393
+ fn take_higher_applicability ( a : Option < usize > , b : Option < usize > ) -> Option < usize > {
394
+ a. map_or ( b, |a| a. max ( b. unwrap_or_default ( ) ) . into ( ) )
395
+ }
396
+
397
+ fn extract_emission_info < ' hir > (
381
398
cx : & LateContext < ' hir > ,
382
399
args : & ' hir [ hir:: Expr < ' hir > ] ,
383
- ) -> Vec < ( String , Option < String > , bool ) > {
384
- let mut lints= Vec :: new ( ) ;
400
+ ) -> Vec < ( String , Option < usize > , bool ) > {
401
+ let mut lints = Vec :: new ( ) ;
385
402
let mut applicability = None ;
386
403
let mut multi_part = false ;
387
404
@@ -401,7 +418,10 @@ fn extract_complex_emission_info<'hir>(
401
418
}
402
419
}
403
420
404
- lints. drain ( ..) . map ( |lint_name| ( lint_name, applicability. clone ( ) , multi_part) ) . collect ( )
421
+ lints
422
+ . drain ( ..)
423
+ . map ( |lint_name| ( lint_name, applicability, multi_part) )
424
+ . collect ( )
405
425
}
406
426
407
427
/// Resolves the possible lints that this expression could reference
@@ -412,7 +432,7 @@ fn resolve_lints(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Vec<Str
412
432
}
413
433
414
434
/// This function tries to resolve the linked applicability to the given expression.
415
- fn resolve_applicability ( cx : & LateContext < ' hir > , expr : & ' hir hir:: Expr < ' hir > ) -> Option < String > {
435
+ fn resolve_applicability ( cx : & LateContext < ' hir > , expr : & ' hir hir:: Expr < ' hir > ) -> Option < usize > {
416
436
let mut resolver = ApplicabilityResolver :: new ( cx) ;
417
437
resolver. visit_expr ( expr) ;
418
438
resolver. complete ( )
@@ -457,7 +477,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> {
457
477
if_chain ! {
458
478
if let ExprKind :: Path ( qpath) = & expr. kind;
459
479
if let QPath :: Resolved ( _, path) = qpath;
460
-
480
+
461
481
let ( expr_ty, _) = walk_ptrs_ty_depth( self . cx. typeck_results( ) . expr_ty( & expr) ) ;
462
482
if match_type( self . cx, expr_ty, & paths:: LINT ) ;
463
483
then {
@@ -492,15 +512,11 @@ impl<'a, 'hir> ApplicabilityResolver<'a, 'hir> {
492
512
}
493
513
494
514
fn add_new_index ( & mut self , new_index : usize ) {
495
- self . applicability_index = self
496
- . applicability_index
497
- . map_or ( new_index, |old_index| old_index. min ( new_index) )
498
- . into ( ) ;
515
+ self . applicability_index = take_higher_applicability ( self . applicability_index , Some ( new_index) ) ;
499
516
}
500
517
501
- fn complete ( self ) -> Option < String > {
518
+ fn complete ( self ) -> Option < usize > {
502
519
self . applicability_index
503
- . map ( |index| paths:: APPLICABILITY_VALUES [ index] [ APPLICABILITY_NAME_INDEX ] . to_string ( ) )
504
520
}
505
521
}
506
522
0 commit comments