about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-08-26 15:56:25 -0700
committerGitHub <noreply@github.com>2022-08-26 15:56:25 -0700
commit389dda149c0524c7d5b8d2020ace3cbc97bda60b (patch)
tree1e7beb3f7a652cbbdac4bd283020c16bdc348e87
parent93b2acd88ace5ab89fdf8c73ac99b7031db6151d (diff)
parent1693993d8ff16b1a5d288bc858db052902126053 (diff)
downloadrust-389dda149c0524c7d5b8d2020ace3cbc97bda60b.tar.gz
rust-389dda149c0524c7d5b8d2020ace3cbc97bda60b.zip
Rollup merge of #100776 - Rejyr:diagnostic-migration-rustc-lint, r=davidtwco
Migrate `rustc_lint` errors to `SessionDiagnostic`

Draft PR for migrating `rustc_lint` to `SessionDiagnostic`, as part of the [recent blog post](https://blog.rust-lang.org/inside-rust/2022/08/16/diagnostic-effort.html)
-rw-r--r--compiler/rustc_error_messages/locales/en-US/lint.ftl34
-rw-r--r--compiler/rustc_lint/src/builtin.rs33
-rw-r--r--compiler/rustc_lint/src/context.rs93
-rw-r--r--compiler/rustc_lint/src/errors.rs162
-rw-r--r--compiler/rustc_lint/src/levels.rs98
-rw-r--r--compiler/rustc_lint/src/lib.rs1
6 files changed, 297 insertions, 124 deletions
diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl
index 97317114716..27ad3e45366 100644
--- a/compiler/rustc_error_messages/locales/en-US/lint.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl
@@ -393,3 +393,37 @@ lint_builtin_deref_nullptr = dereferencing a null pointer
     .label = this code causes undefined behavior when executed
 
 lint_builtin_asm_labels = avoid using named labels in inline assembly
+
+lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid
+    .label = overruled by previous forbid
+
+lint_default_source = `forbid` lint level is the default for {$id}
+
+lint_node_source = `forbid` level set here
+    .note = {$reason}
+
+lint_command_line_source = `forbid` lint level was set on command line
+
+lint_malformed_attribute = malformed lint attribute input
+
+lint_bad_attribute_argument = bad attribute argument
+
+lint_reason_must_be_string_literal = reason must be a string literal
+
+lint_reason_must_come_last = reason in lint attribute must come last
+
+lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
+    .help = add `#![register_tool({$tool_name})]` to the crate root
+
+lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
+
+lint_requested_level = requested on the command line with `{$level} {$lint_name}`
+
+lint_check_name_unknown = unknown lint: `{$lint_name}`
+    .help = did you mean: `{$suggestion}`
+
+lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
+
+lint_check_name_warning = {$msg}
+
+lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index bd58021f78f..af7ef96e485 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -21,6 +21,7 @@
 //! `late_lint_methods!` invocation in `lib.rs`.
 
 use crate::{
+    errors::BuiltinEllpisisInclusiveRangePatterns,
     types::{transparent_newtype_field, CItemKind},
     EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
 };
@@ -1760,18 +1761,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
                     None => format!("&(..={})", end),
                 };
                 if join.edition() >= Edition::Edition2021 {
-                    let mut err = cx.sess().struct_span_err_with_code(
-                        pat.span,
-                        msg,
-                        rustc_errors::error_code!(E0783),
-                    );
-                    err.span_suggestion(
-                        pat.span,
-                        suggestion,
+                    cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
+                        span: pat.span,
+                        suggestion: pat.span,
                         replace,
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
+                    });
                 } else {
                     cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
                         lint.build(msg)
@@ -1787,18 +1781,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
             } else {
                 let replace = "..=";
                 if join.edition() >= Edition::Edition2021 {
-                    let mut err = cx.sess().struct_span_err_with_code(
-                        pat.span,
-                        msg,
-                        rustc_errors::error_code!(E0783),
-                    );
-                    err.span_suggestion_short(
-                        join,
-                        suggestion,
-                        replace,
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
+                    cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
+                        span: pat.span,
+                        suggestion: join,
+                        replace: replace.to_string(),
+                    });
                 } else {
                     cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
                         lint.build(msg)
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 6586fe440f3..002bba4759b 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -16,12 +16,16 @@
 
 use self::TargetLint::*;
 
+use crate::errors::{
+    CheckNameDeprecated, CheckNameUnknown, CheckNameUnknownTool, CheckNameWarning, RequestedLevel,
+    UnsupportedGroup,
+};
 use crate::levels::LintLevelsBuilder;
 use crate::passes::{EarlyLintPassObject, LateLintPassObject};
 use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync;
-use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err};
+use rustc_errors::add_elided_lifetime_in_path_suggestion;
 use rustc_errors::{
     Applicability, DecorateLint, LintDiagnosticBuilder, MultiSpan, SuggestionStyle,
 };
@@ -39,7 +43,7 @@ use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintI
 use rustc_session::Session;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{BytePos, Span, DUMMY_SP};
+use rustc_span::{BytePos, Span};
 use rustc_target::abi;
 use tracing::debug;
 
@@ -326,68 +330,41 @@ impl LintStore {
     ) {
         let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
         if lint_name_only == crate::WARNINGS.name_lower() && matches!(level, Level::ForceWarn(_)) {
-            struct_span_err!(
-                sess,
-                DUMMY_SP,
-                E0602,
-                "`{}` lint group is not supported with ´--force-warn´",
-                crate::WARNINGS.name_lower()
-            )
-            .emit();
+            sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
             return;
         }
-        let db = match self.check_lint_name(lint_name_only, tool_name, registered_tools) {
-            CheckLintNameResult::Ok(_) => None,
-            CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
+        let lint_name = lint_name.to_string();
+        match self.check_lint_name(lint_name_only, tool_name, registered_tools) {
+            CheckLintNameResult::Warning(msg, _) => {
+                sess.emit_warning(CheckNameWarning {
+                    msg,
+                    sub: RequestedLevel { level, lint_name },
+                });
+            }
             CheckLintNameResult::NoLint(suggestion) => {
-                let mut err =
-                    struct_span_err!(sess, DUMMY_SP, E0602, "unknown lint: `{}`", lint_name);
-
-                if let Some(suggestion) = suggestion {
-                    err.help(&format!("did you mean: `{}`", suggestion));
+                sess.emit_err(CheckNameUnknown {
+                    lint_name: lint_name.clone(),
+                    suggestion,
+                    sub: RequestedLevel { level, lint_name },
+                });
+            }
+            CheckLintNameResult::Tool(result) => {
+                if let Err((Some(_), new_name)) = result {
+                    sess.emit_warning(CheckNameDeprecated {
+                        lint_name: lint_name.clone(),
+                        new_name,
+                        sub: RequestedLevel { level, lint_name },
+                    });
                 }
-
-                Some(err.forget_guarantee())
             }
-            CheckLintNameResult::Tool(result) => match result {
-                Err((Some(_), new_name)) => Some(sess.struct_warn(&format!(
-                    "lint name `{}` is deprecated \
-                     and does not have an effect anymore. \
-                     Use: {}",
-                    lint_name, new_name
-                ))),
-                _ => None,
-            },
-            CheckLintNameResult::NoTool => Some(
-                struct_span_err!(
-                    sess,
-                    DUMMY_SP,
-                    E0602,
-                    "unknown lint tool: `{}`",
-                    tool_name.unwrap()
-                )
-                .forget_guarantee(),
-            ),
+            CheckLintNameResult::NoTool => {
+                sess.emit_err(CheckNameUnknownTool {
+                    tool_name: tool_name.unwrap(),
+                    sub: RequestedLevel { level, lint_name },
+                });
+            }
+            _ => {}
         };
-
-        if let Some(mut db) = db {
-            let msg = format!(
-                "requested on the command line with `{} {}`",
-                match level {
-                    Level::Allow => "-A",
-                    Level::Warn => "-W",
-                    Level::ForceWarn(_) => "--force-warn",
-                    Level::Deny => "-D",
-                    Level::Forbid => "-F",
-                    Level::Expect(_) => {
-                        unreachable!("lints with the level of `expect` should not run this code");
-                    }
-                },
-                lint_name
-            );
-            db.note(&msg);
-            db.emit();
-        }
     }
 
     /// True if this symbol represents a lint group name.
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
new file mode 100644
index 00000000000..606d8bda8aa
--- /dev/null
+++ b/compiler/rustc_lint/src/errors.rs
@@ -0,0 +1,162 @@
+use rustc_errors::{fluent, AddSubdiagnostic, ErrorGuaranteed};
+use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
+use rustc_session::{lint::Level, parse::ParseSess, SessionDiagnostic};
+use rustc_span::{Span, Symbol};
+
+#[derive(SessionDiagnostic)]
+#[diag(lint::overruled_attribute, code = "E0453")]
+pub struct OverruledAttribute {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub overruled: Span,
+    pub lint_level: String,
+    pub lint_source: Symbol,
+    #[subdiagnostic]
+    pub sub: OverruledAttributeSub,
+}
+//
+pub enum OverruledAttributeSub {
+    DefaultSource { id: String },
+    NodeSource { span: Span, reason: Option<Symbol> },
+    CommandLineSource,
+}
+
+impl AddSubdiagnostic for OverruledAttributeSub {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        match self {
+            OverruledAttributeSub::DefaultSource { id } => {
+                diag.note(fluent::lint::default_source);
+                diag.set_arg("id", id);
+            }
+            OverruledAttributeSub::NodeSource { span, reason } => {
+                diag.span_label(span, fluent::lint::node_source);
+                if let Some(rationale) = reason {
+                    diag.note(rationale.as_str());
+                }
+            }
+            OverruledAttributeSub::CommandLineSource => {
+                diag.note(fluent::lint::command_line_source);
+            }
+        }
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(lint::malformed_attribute, code = "E0452")]
+pub struct MalformedAttribute {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sub: MalformedAttributeSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum MalformedAttributeSub {
+    #[label(lint::bad_attribute_argument)]
+    BadAttributeArgument(#[primary_span] Span),
+    #[label(lint::reason_must_be_string_literal)]
+    ReasonMustBeStringLiteral(#[primary_span] Span),
+    #[label(lint::reason_must_come_last)]
+    ReasonMustComeLast(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(lint::unknown_tool_in_scoped_lint, code = "E0710")]
+pub struct UnknownToolInScopedLint {
+    #[primary_span]
+    pub span: Option<Span>,
+    pub tool_name: Symbol,
+    pub lint_name: String,
+    #[help]
+    pub is_nightly_build: Option<()>,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(lint::builtin_ellipsis_inclusive_range_patterns, code = "E0783")]
+pub struct BuiltinEllpisisInclusiveRangePatterns {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion_short(code = "{replace}", applicability = "machine-applicable")]
+    pub suggestion: Span,
+    pub replace: String,
+}
+
+pub struct RequestedLevel {
+    pub level: Level,
+    pub lint_name: String,
+}
+
+impl AddSubdiagnostic for RequestedLevel {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        diag.note(fluent::lint::requested_level);
+        diag.set_arg(
+            "level",
+            match self.level {
+                Level::Allow => "-A",
+                Level::Warn => "-W",
+                Level::ForceWarn(_) => "--force-warn",
+                Level::Deny => "-D",
+                Level::Forbid => "-F",
+                Level::Expect(_) => {
+                    unreachable!("lints with the level of `expect` should not run this code");
+                }
+            },
+        );
+        diag.set_arg("lint_name", self.lint_name);
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(lint::unsupported_group, code = "E0602")]
+pub struct UnsupportedGroup {
+    pub lint_group: String,
+}
+
+pub struct CheckNameUnknown {
+    pub lint_name: String,
+    pub suggestion: Option<Symbol>,
+    pub sub: RequestedLevel,
+}
+
+impl SessionDiagnostic<'_> for CheckNameUnknown {
+    fn into_diagnostic(
+        self,
+        sess: &ParseSess,
+    ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = sess.struct_err(fluent::lint::check_name_unknown);
+        diag.code(rustc_errors::error_code!(E0602));
+        if let Some(suggestion) = self.suggestion {
+            diag.help(fluent::lint::help);
+            diag.set_arg("suggestion", suggestion);
+        }
+        diag.set_arg("lint_name", self.lint_name);
+        diag.subdiagnostic(self.sub);
+        diag
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(lint::check_name_unknown_tool, code = "E0602")]
+pub struct CheckNameUnknownTool {
+    pub tool_name: Symbol,
+    #[subdiagnostic]
+    pub sub: RequestedLevel,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(lint::check_name_warning)]
+pub struct CheckNameWarning {
+    pub msg: String,
+    #[subdiagnostic]
+    pub sub: RequestedLevel,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(lint::check_name_deprecated)]
+pub struct CheckNameDeprecated {
+    pub lint_name: String,
+    pub new_name: String,
+    #[subdiagnostic]
+    pub sub: RequestedLevel,
+}
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 1cabb58bbeb..89409b58f88 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -3,7 +3,7 @@ use crate::late::unerased_lint_store;
 use rustc_ast as ast;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, LintDiagnosticBuilder, MultiSpan};
+use rustc_errors::{Applicability, Diagnostic, LintDiagnosticBuilder, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::{intravisit, HirId};
 use rustc_middle::hir::nested_filter;
@@ -23,6 +23,11 @@ use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use tracing::debug;
 
+use crate::errors::{
+    MalformedAttribute, MalformedAttributeSub, OverruledAttribute, OverruledAttributeSub,
+    UnknownToolInScopedLint,
+};
+
 fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap {
     let store = unerased_lint_store(tcx);
     let levels =
@@ -186,16 +191,26 @@ impl<'s> LintLevelsBuilder<'s> {
                     }
                 };
                 if !fcw_warning {
-                    let mut diag_builder = struct_span_err!(
-                        self.sess,
-                        src.span(),
-                        E0453,
-                        "{}({}) incompatible with previous forbid",
-                        level.as_str(),
-                        src.name(),
-                    );
-                    decorate_diag(&mut diag_builder);
-                    diag_builder.emit();
+                    self.sess.emit_err(OverruledAttribute {
+                        span: src.span(),
+                        overruled: src.span(),
+                        lint_level: level.as_str().to_string(),
+                        lint_source: src.name(),
+                        sub: match old_src {
+                            LintLevelSource::Default => {
+                                OverruledAttributeSub::DefaultSource { id: id.to_string() }
+                            }
+                            LintLevelSource::Node(_, forbid_source_span, reason) => {
+                                OverruledAttributeSub::NodeSource {
+                                    span: forbid_source_span,
+                                    reason,
+                                }
+                            }
+                            LintLevelSource::CommandLine(_, _) => {
+                                OverruledAttributeSub::CommandLineSource
+                            }
+                        },
+                    });
                 } else {
                     self.struct_lint(
                         FORBIDDEN_LINT_GROUPS,
@@ -266,7 +281,6 @@ impl<'s> LintLevelsBuilder<'s> {
         self.cur = self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev });
 
         let sess = self.sess;
-        let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
         for (attr_index, attr) in attrs.iter().enumerate() {
             if attr.has_name(sym::automatically_derived) {
                 self.current_specs_mut().insert(
@@ -317,20 +331,27 @@ impl<'s> LintLevelsBuilder<'s> {
                                 }
                                 reason = Some(rationale);
                             } else {
-                                bad_attr(name_value.span)
-                                    .span_label(name_value.span, "reason must be a string literal")
-                                    .emit();
+                                sess.emit_err(MalformedAttribute {
+                                    span: name_value.span,
+                                    sub: MalformedAttributeSub::ReasonMustBeStringLiteral(
+                                        name_value.span,
+                                    ),
+                                });
                             }
                             // found reason, reslice meta list to exclude it
                             metas.pop().unwrap();
                         } else {
-                            bad_attr(item.span)
-                                .span_label(item.span, "bad attribute argument")
-                                .emit();
+                            sess.emit_err(MalformedAttribute {
+                                span: item.span,
+                                sub: MalformedAttributeSub::BadAttributeArgument(item.span),
+                            });
                         }
                     }
                     ast::MetaItemKind::List(_) => {
-                        bad_attr(item.span).span_label(item.span, "bad attribute argument").emit();
+                        sess.emit_err(MalformedAttribute {
+                            span: item.span,
+                            sub: MalformedAttributeSub::BadAttributeArgument(item.span),
+                        });
                     }
                 }
             }
@@ -348,20 +369,21 @@ impl<'s> LintLevelsBuilder<'s> {
                 let meta_item = match li {
                     ast::NestedMetaItem::MetaItem(meta_item) if meta_item.is_word() => meta_item,
                     _ => {
-                        let mut err = bad_attr(sp);
-                        let mut add_label = true;
                         if let Some(item) = li.meta_item() {
                             if let ast::MetaItemKind::NameValue(_) = item.kind {
                                 if item.path == sym::reason {
-                                    err.span_label(sp, "reason in lint attribute must come last");
-                                    add_label = false;
+                                    sess.emit_err(MalformedAttribute {
+                                        span: sp,
+                                        sub: MalformedAttributeSub::ReasonMustComeLast(sp),
+                                    });
+                                    continue;
                                 }
                             }
                         }
-                        if add_label {
-                            err.span_label(sp, "bad attribute argument");
-                        }
-                        err.emit();
+                        sess.emit_err(MalformedAttribute {
+                            span: sp,
+                            sub: MalformedAttributeSub::BadAttributeArgument(sp),
+                        });
                         continue;
                     }
                 };
@@ -485,22 +507,12 @@ impl<'s> LintLevelsBuilder<'s> {
                     }
 
                     &CheckLintNameResult::NoTool => {
-                        let mut err = struct_span_err!(
-                            sess,
-                            tool_ident.map_or(DUMMY_SP, |ident| ident.span),
-                            E0710,
-                            "unknown tool name `{}` found in scoped lint: `{}::{}`",
-                            tool_name.unwrap(),
-                            tool_name.unwrap(),
-                            pprust::path_to_string(&meta_item.path),
-                        );
-                        if sess.is_nightly_build() {
-                            err.help(&format!(
-                                "add `#![register_tool({})]` to the crate root",
-                                tool_name.unwrap()
-                            ));
-                        }
-                        err.emit();
+                        sess.emit_err(UnknownToolInScopedLint {
+                            span: tool_ident.map(|ident| ident.span),
+                            tool_name: tool_name.unwrap(),
+                            lint_name: pprust::path_to_string(&meta_item.path),
+                            is_nightly_build: sess.is_nightly_build().then_some(()),
+                        });
                         continue;
                     }
 
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index f087c624917..f34e062fd12 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -47,6 +47,7 @@ pub mod builtin;
 mod context;
 mod early;
 mod enum_intrinsics_non_enums;
+mod errors;
 mod expect;
 pub mod hidden_unicode_codepoints;
 mod internal;