@@ -30,10 +30,15 @@ use rustc_span::source_map::SourceMap;
30
30
use rustc_span:: { Loc , MultiSpan , Span } ;
31
31
32
32
use std:: borrow:: Cow ;
33
+ use std:: clone:: Clone ;
34
+ use std:: convert:: TryFrom ;
33
35
use std:: hash:: { Hash , Hasher } ;
36
+ use std:: iter:: Iterator ;
37
+ use std:: mem:: take;
34
38
use std:: num:: NonZeroUsize ;
35
39
use std:: panic;
36
40
use std:: path:: Path ;
41
+ use std:: result:: Result :: Ok ;
37
42
use std:: { error, fmt} ;
38
43
39
44
use termcolor:: { Color , ColorSpec } ;
@@ -332,6 +337,10 @@ struct HandlerInner {
332
337
/// twice.
333
338
emitted_diagnostics : FxHashSet < u128 > ,
334
339
340
+ /// This contains all lint emission information from this compiling session
341
+ /// with the emission level `Expect`.
342
+ expected_lint_emissions : Vec < LintEmission > ,
343
+
335
344
/// Stashed diagnostics emitted in one stage of the compiler that may be
336
345
/// stolen by other stages (e.g. to improve them and add more information).
337
346
/// The stashed diagnostics count towards the total error count.
@@ -454,6 +463,7 @@ impl Handler {
454
463
taught_diagnostics : Default :: default ( ) ,
455
464
emitted_diagnostic_codes : Default :: default ( ) ,
456
465
emitted_diagnostics : Default :: default ( ) ,
466
+ expected_lint_emissions : Vec :: new ( ) ,
457
467
stashed_diagnostics : Default :: default ( ) ,
458
468
future_breakage_diagnostics : Vec :: new ( ) ,
459
469
} ) ,
@@ -805,6 +815,14 @@ impl Handler {
805
815
pub fn delay_as_bug ( & self , diagnostic : Diagnostic ) {
806
816
self . inner . borrow_mut ( ) . delay_as_bug ( diagnostic)
807
817
}
818
+
819
+ /// This method takes all lint emission information that have been issued from
820
+ /// by `HandlerInner` in this session. This will steal the collection from the
821
+ /// internal handler and should therefore only be used to check for expected
822
+ /// lints. (RFC 2383)
823
+ pub fn steal_expect_lint_emissions ( & self ) -> Vec < LintEmission > {
824
+ take ( & mut self . inner . borrow_mut ( ) . expected_lint_emissions )
825
+ }
808
826
}
809
827
810
828
impl HandlerInner {
@@ -861,6 +879,14 @@ impl HandlerInner {
861
879
// Only emit the diagnostic if we've been asked to deduplicate and
862
880
// haven't already emitted an equivalent diagnostic.
863
881
if !( self . flags . deduplicate_diagnostics && already_emitted ( self ) ) {
882
+ if diagnostic. level == Level :: Expect {
883
+ if let Ok ( emission) = LintEmission :: try_from ( diagnostic) {
884
+ self . expected_lint_emissions . push ( emission) ;
885
+ }
886
+ // Diagnostics with the level `Expect` shouldn't be emitted or effect internal counters.
887
+ return ;
888
+ }
889
+
864
890
self . emitter . emit_diagnostic ( diagnostic) ;
865
891
if diagnostic. is_error ( ) {
866
892
self . deduplicated_err_count += 1 ;
@@ -1095,6 +1121,70 @@ impl DelayedDiagnostic {
1095
1121
}
1096
1122
}
1097
1123
1124
+ /// Used to track all emitted lints to later evaluate if expected lints have been
1125
+ /// emitted.
1126
+ #[ must_use]
1127
+ #[ derive( Clone , Debug , PartialEq , Hash ) ]
1128
+ pub struct LintEmission {
1129
+ /// The lint name that was emitted.
1130
+ pub lint_name : String ,
1131
+
1132
+ /// The spans of the emission.
1133
+ ///
1134
+ /// FIXME: We should define which span is taken from the diagnostic, this simply takes all spans
1135
+ // until that is defined (xFrednet 2021-06-03)
1136
+ pub lint_span : MultiSpan ,
1137
+ }
1138
+
1139
+ impl TryFrom < & Diagnostic > for LintEmission {
1140
+ type Error = ( ) ;
1141
+
1142
+ fn try_from ( diagnostic : & Diagnostic ) -> Result < Self , Self :: Error > {
1143
+ if let Some ( DiagnosticId :: Lint { name, .. } ) = & diagnostic. code {
1144
+ Ok ( LintEmission { lint_name : name. clone ( ) , lint_span : extract_all_spans ( diagnostic) } )
1145
+ } else {
1146
+ Err ( ( ) )
1147
+ }
1148
+ }
1149
+ }
1150
+
1151
+ fn extract_all_spans ( source : & Diagnostic ) -> MultiSpan {
1152
+ let mut result = Vec :: new ( ) ;
1153
+
1154
+ result. append ( & mut extract_spans_from_multispan ( & source. span ) ) ;
1155
+
1156
+ // Some lints only have a suggestion span. Example: unused_variables
1157
+ for sugg in & source. suggestions {
1158
+ for substitution in & sugg. substitutions {
1159
+ for part in & substitution. parts {
1160
+ result. push ( part. span ) ;
1161
+ }
1162
+ }
1163
+ }
1164
+
1165
+ // Some lints only have `SubDiagnostic`s. Example: const_item_mutation
1166
+ for sub in & source. children {
1167
+ result. append ( & mut extract_spans_from_multispan ( & sub. span ) ) ;
1168
+ }
1169
+
1170
+ MultiSpan :: from_spans ( result)
1171
+ }
1172
+
1173
+ fn extract_spans_from_multispan ( source : & MultiSpan ) -> Vec < Span > {
1174
+ let mut result: Vec < Span > = source. primary_spans ( ) . into ( ) ;
1175
+
1176
+ // Some lints only have span_lints for notes. Example: clashing_extern_declarations
1177
+ result. extend (
1178
+ source
1179
+ . span_labels ( )
1180
+ . iter ( )
1181
+ . filter ( |span| span. is_primary )
1182
+ . map ( |span_label| span_label. span ) ,
1183
+ ) ;
1184
+
1185
+ result
1186
+ }
1187
+
1098
1188
#[ derive( Copy , PartialEq , Clone , Hash , Debug , Encodable , Decodable ) ]
1099
1189
pub enum Level {
1100
1190
Bug ,
0 commit comments