77//! The module transforms all lint names to ascii lowercase to ensure that we don't have mismatches
88//! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
99//! 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+
2711// # NITs
2812// - TODO xFrednet 2021-02-13: Collect depreciations and maybe renames
2913
3014use if_chain:: if_chain;
3115use 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+ } ;
3319use rustc_lint:: { CheckLintNameResult , LateContext , LateLintPass , LintContext , LintId } ;
3420use rustc_middle:: hir:: map:: Map ;
3521use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
3622use rustc_span:: { sym, Loc , Span , Symbol } ;
37- use serde:: Serialize ;
23+ use serde:: { ser:: SerializeStruct , Serialize , Serializer } ;
24+ use std:: collections:: BinaryHeap ;
3825use std:: fs:: { self , OpenOptions } ;
3926use std:: io:: prelude:: * ;
4027use std:: path:: Path ;
@@ -47,7 +34,7 @@ use crate::utils::{
4734/// This is the output file of the lint collector.
4835const OUTPUT_FILE : & str = "../metadata_collection.json" ;
4936/// 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 "] ;
5138/// These groups will be ignored by the lint group matcher. This is useful for collections like
5239/// `clippy::all`
5340const IGNORED_LINT_GROUPS : [ & str ; 1 ] = [ "clippy::all" ] ;
@@ -107,7 +94,7 @@ declare_clippy_lint! {
10794 /// }
10895 /// ```
10996 pub INTERNAL_METADATA_COLLECTOR ,
110- internal ,
97+ internal_warn ,
11198 "A busy bee collection metadata about lints"
11299}
113100
@@ -116,22 +103,28 @@ impl_lint_pass!(MetadataCollector => [INTERNAL_METADATA_COLLECTOR]);
116103#[ allow( clippy:: module_name_repetitions) ]
117104#[ derive( Debug , Clone , Default ) ]
118105pub 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 > ,
120110 applicability_into : FxHashMap < String , ApplicabilityInfo > ,
121111}
122112
123113impl Drop for MetadataCollector {
124114 /// You might ask: How hacky is this?
125115 /// My answer: YES
126116 fn drop ( & mut self ) {
117+ // The metadata collector gets dropped twice, this makes sure that we only write
118+ // when the list is full
127119 if self . lints . is_empty ( ) {
128120 return ;
129121 }
130122
131123 let mut applicability_info = std:: mem:: take ( & mut self . applicability_into ) ;
132124
133125 // Mapping the final data
134- self . lints
126+ let mut lints = std:: mem:: take ( & mut self . lints ) . into_sorted_vec ( ) ;
127+ lints
135128 . iter_mut ( )
136129 . for_each ( |x| x. applicability = applicability_info. remove ( & x. id ) ) ;
137130
@@ -140,11 +133,11 @@ impl Drop for MetadataCollector {
140133 fs:: remove_file ( OUTPUT_FILE ) . unwrap ( ) ;
141134 }
142135 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 ( ) ;
144137 }
145138}
146139
147- #[ derive( Debug , Clone , Serialize ) ]
140+ #[ derive( Debug , Clone , Serialize , PartialEq , Eq , PartialOrd , Ord ) ]
148141struct LintMetadata {
149142 id : String ,
150143 id_span : SerializableSpan ,
@@ -155,6 +148,24 @@ struct LintMetadata {
155148 applicability : Option < ApplicabilityInfo > ,
156149}
157150
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+
158169impl LintMetadata {
159170 fn new ( id : String , id_span : SerializableSpan , group : String , docs : String ) -> Self {
160171 Self {
@@ -167,7 +178,7 @@ impl LintMetadata {
167178 }
168179}
169180
170- #[ derive( Debug , Clone , Serialize ) ]
181+ #[ derive( Debug , Clone , Serialize , PartialEq , Eq , PartialOrd , Ord ) ]
171182struct SerializableSpan {
172183 path : String ,
173184 line : usize ,
@@ -194,25 +205,30 @@ impl SerializableSpan {
194205 }
195206}
196207
197- #[ derive( Debug , Clone , Default , Serialize ) ]
208+ #[ derive( Debug , Clone , Default , PartialEq , Eq , PartialOrd , Ord ) ]
198209struct ApplicabilityInfo {
199210 /// Indicates if any of the lint emissions uses multiple spans. This is related to
200211 /// [rustfix#141](https://github.com/rust-lang/rustfix/issues/141) as such suggestions can
201212 /// 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+ }
216232}
217233
218234impl < ' hir > LateLintPass < ' hir > for MetadataCollector {
@@ -266,16 +282,20 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
266282 /// ```
267283 fn check_expr ( & mut self , cx : & LateContext < ' hir > , expr : & ' hir hir:: Expr < ' _ > ) {
268284 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) ;
270286 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.
272292 return ;
273293 }
274294
275295 for ( lint_name, applicability, is_multi_part) in emission_info. drain ( ..) {
276296 let app_info = self . applicability_into . entry ( lint_name) . or_default ( ) ;
277297 app_info. applicability = applicability;
278- app_info. is_multi_suggestion = is_multi_part;
298+ app_info. is_multi_part_suggestion = is_multi_part;
279299 }
280300 }
281301 }
@@ -289,7 +309,7 @@ fn sym_to_string(sym: Symbol) -> String {
289309}
290310
291311fn 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 ( || {
293313 lint_collection_error_item ( cx, item, "could not collect the lint documentation" ) ;
294314 None
295315 } )
@@ -305,8 +325,10 @@ fn extract_attr_docs_or_lint(cx: &LateContext<'_>, item: &Item<'_>) -> Option<St
305325/// ```
306326///
307327/// 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 ( ) )
310332 . iter ( )
311333 . filter_map ( |ref x| x. doc_str ( ) . map ( |sym| sym. as_str ( ) . to_string ( ) ) )
312334 . reduce ( |mut acc, sym| {
@@ -357,15 +379,6 @@ fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &s
357379 ) ;
358380}
359381
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-
369382// ==================================================================
370383// Applicability
371384// ==================================================================
@@ -377,11 +390,15 @@ fn match_lint_emission<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>)
377390 . find_map ( |emission_fn| match_function_call ( cx, expr, emission_fn) )
378391}
379392
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 > (
381398 cx : & LateContext < ' hir > ,
382399 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 ( ) ;
385402 let mut applicability = None ;
386403 let mut multi_part = false ;
387404
@@ -401,7 +418,10 @@ fn extract_complex_emission_info<'hir>(
401418 }
402419 }
403420
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 ( )
405425}
406426
407427/// 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
412432}
413433
414434/// 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 > {
416436 let mut resolver = ApplicabilityResolver :: new ( cx) ;
417437 resolver. visit_expr ( expr) ;
418438 resolver. complete ( )
@@ -457,7 +477,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> {
457477 if_chain ! {
458478 if let ExprKind :: Path ( qpath) = & expr. kind;
459479 if let QPath :: Resolved ( _, path) = qpath;
460-
480+
461481 let ( expr_ty, _) = walk_ptrs_ty_depth( self . cx. typeck_results( ) . expr_ty( & expr) ) ;
462482 if match_type( self . cx, expr_ty, & paths:: LINT ) ;
463483 then {
@@ -492,15 +512,11 @@ impl<'a, 'hir> ApplicabilityResolver<'a, 'hir> {
492512 }
493513
494514 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) ) ;
499516 }
500517
501- fn complete ( self ) -> Option < String > {
518+ fn complete ( self ) -> Option < usize > {
502519 self . applicability_index
503- . map ( |index| paths:: APPLICABILITY_VALUES [ index] [ APPLICABILITY_NAME_INDEX ] . to_string ( ) )
504520 }
505521}
506522
0 commit comments