use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId};
+use rustc_errors::{
+ Diagnostic, DiagnosticBuilder, DiagnosticId, EmissionGuarantee, ErrorGuaranteed,
+};
use rustc_hir::HirId;
use rustc_index::vec::IndexVec;
use rustc_query_system::ich::StableHashingContext;
builtin::{self, FORBIDDEN_LINT_GROUPS},
FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId,
};
-use rustc_session::{DiagnosticMessageId, Session};
+use rustc_session::Session;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
use rustc_span::{symbol, Span, Symbol, DUMMY_SP};
pub reason: Option<Symbol>,
/// The [`Span`] of the attribute that this expectation originated from.
pub emission_span: Span,
+ /// Lint messages for the `unfulfilled_lint_expectations` lint will be
+ /// adjusted to include an additional note. Therefore, we have to track if
+ /// the expectation is for the lint.
+ pub is_unfulfilled_lint_expectations: bool,
}
impl LintExpectation {
- pub fn new(reason: Option<Symbol>, attr_span: Span) -> Self {
- Self { reason, emission_span: attr_span }
+ pub fn new(
+ reason: Option<Symbol>,
+ emission_span: Span,
+ is_unfulfilled_lint_expectations: bool,
+ ) -> Self {
+ Self { reason, emission_span, is_unfulfilled_lint_expectations }
}
}
-pub struct LintDiagnosticBuilder<'a>(DiagnosticBuilder<'a, ()>);
+pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a, G>);
-impl<'a> LintDiagnosticBuilder<'a> {
- /// Return the inner DiagnosticBuilder, first setting the primary message to `msg`.
- pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a, ()> {
+impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> {
+ /// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`.
+ pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a, G> {
self.0.set_primary_message(msg);
self.0.set_is_lint();
self.0
}
- /// Create a LintDiagnosticBuilder from some existing DiagnosticBuilder.
- pub fn new(err: DiagnosticBuilder<'a, ()>) -> LintDiagnosticBuilder<'a> {
+ /// Create a `LintDiagnosticBuilder` from some existing `DiagnosticBuilder`.
+ pub fn new(err: DiagnosticBuilder<'a, G>) -> LintDiagnosticBuilder<'a, G> {
LintDiagnosticBuilder(err)
}
}
+impl<'a> LintDiagnosticBuilder<'a, ErrorGuaranteed> {
+ pub fn forget_guarantee(self) -> LintDiagnosticBuilder<'a, ()> {
+ LintDiagnosticBuilder(self.0.forget_guarantee())
+ }
+}
+
pub fn explain_lint_level_source(
- sess: &Session,
lint: &'static Lint,
level: Level,
src: LintLevelSource,
let name = lint.name_lower();
match src {
LintLevelSource::Default => {
- sess.diag_note_once(
- err,
- DiagnosticMessageId::from(lint),
- &format!("`#[{}({})]` on by default", level.as_str(), name),
- );
+ err.note_once(&format!("`#[{}({})]` on by default", level.as_str(), name));
}
LintLevelSource::CommandLine(lint_flag_val, orig_level) => {
let flag = match orig_level {
};
let hyphen_case_lint_name = name.replace('_', "-");
if lint_flag_val.as_str() == name {
- sess.diag_note_once(
- err,
- DiagnosticMessageId::from(lint),
- &format!(
- "requested on the command line with `{} {}`",
- flag, hyphen_case_lint_name
- ),
- );
+ err.note_once(&format!(
+ "requested on the command line with `{} {}`",
+ flag, hyphen_case_lint_name
+ ));
} else {
let hyphen_case_flag_val = lint_flag_val.as_str().replace('_', "-");
- sess.diag_note_once(
- err,
- DiagnosticMessageId::from(lint),
- &format!(
- "`{} {}` implied by `{} {}`",
- flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
- ),
- );
+ err.note_once(&format!(
+ "`{} {}` implied by `{} {}`",
+ flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
+ ));
}
}
LintLevelSource::Node(lint_attr_name, src, reason) => {
if let Some(rationale) = reason {
err.note(rationale.as_str());
}
- sess.diag_span_note_once(
- err,
- DiagnosticMessageId::from(lint),
- src,
- "the lint level is defined here",
- );
+ err.span_note_once(src, "the lint level is defined here");
if lint_attr_name.as_str() != name {
let level_str = level.as_str();
- sess.diag_note_once(
- err,
- DiagnosticMessageId::from(lint),
- &format!(
- "`#[{}({})]` implied by `#[{}({})]`",
- level_str, name, level_str, lint_attr_name
- ),
- );
+ err.note_once(&format!(
+ "`#[{}({})]` implied by `#[{}({})]`",
+ level_str, name, level_str, lint_attr_name
+ ));
}
}
}
level: Level,
src: LintLevelSource,
span: Option<MultiSpan>,
- decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd,
+ decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>) + 'd,
) {
// Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to
// the "real" work.
level: Level,
src: LintLevelSource,
span: Option<MultiSpan>,
- decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>,
+ decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b, ()>) + 'd>,
) {
// Check for future incompatibility lints and issue a stronger warning.
let future_incompatible = lint.future_incompatible;
return;
}
- explain_lint_level_source(sess, lint, level, src, &mut err);
+ explain_lint_level_source(lint, level, src, &mut err);
let name = lint.name_lower();
let is_force_warn = matches!(level, Level::ForceWarn);