Skip to content

Commit 9066544

Browse files
committed
Collect diagnostics with level expect (RFC 2383)
1 parent 243029b commit 9066544

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed

compiler/rustc_errors/src/lib.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,15 @@ use rustc_span::source_map::SourceMap;
3030
use rustc_span::{Loc, MultiSpan, Span};
3131

3232
use std::borrow::Cow;
33+
use std::clone::Clone;
34+
use std::convert::TryFrom;
3335
use std::hash::{Hash, Hasher};
36+
use std::iter::Iterator;
37+
use std::mem::take;
3438
use std::num::NonZeroUsize;
3539
use std::panic;
3640
use std::path::Path;
41+
use std::result::Result::Ok;
3742
use std::{error, fmt};
3843

3944
use termcolor::{Color, ColorSpec};
@@ -332,6 +337,10 @@ struct HandlerInner {
332337
/// twice.
333338
emitted_diagnostics: FxHashSet<u128>,
334339

340+
/// This contains all lint emission information from this compiling session
341+
/// with the emission level `Expect`.
342+
expected_lint_emissions: Vec<LintEmission>,
343+
335344
/// Stashed diagnostics emitted in one stage of the compiler that may be
336345
/// stolen by other stages (e.g. to improve them and add more information).
337346
/// The stashed diagnostics count towards the total error count.
@@ -454,6 +463,7 @@ impl Handler {
454463
taught_diagnostics: Default::default(),
455464
emitted_diagnostic_codes: Default::default(),
456465
emitted_diagnostics: Default::default(),
466+
expected_lint_emissions: Vec::new(),
457467
stashed_diagnostics: Default::default(),
458468
future_breakage_diagnostics: Vec::new(),
459469
}),
@@ -805,6 +815,14 @@ impl Handler {
805815
pub fn delay_as_bug(&self, diagnostic: Diagnostic) {
806816
self.inner.borrow_mut().delay_as_bug(diagnostic)
807817
}
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+
}
808826
}
809827

810828
impl HandlerInner {
@@ -861,6 +879,14 @@ impl HandlerInner {
861879
// Only emit the diagnostic if we've been asked to deduplicate and
862880
// haven't already emitted an equivalent diagnostic.
863881
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+
864890
self.emitter.emit_diagnostic(diagnostic);
865891
if diagnostic.is_error() {
866892
self.deduplicated_err_count += 1;
@@ -1095,6 +1121,70 @@ impl DelayedDiagnostic {
10951121
}
10961122
}
10971123

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+
10981188
#[derive(Copy, PartialEq, Clone, Hash, Debug, Encodable, Decodable)]
10991189
pub enum Level {
11001190
Bug,

src/test/ui/lint/rfc-2383-lint-reason/expect_enabled_feature_gate.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44

55
// should be fine due to the enabled feature gate
66
#[expect(unused_variables)]
7-
fn main() {}
7+
fn main() {
8+
let x = 2;
9+
}

0 commit comments

Comments
 (0)