1
Fork 0

Access TyCtxt from early diagnostic decoration

This commit is contained in:
Urgau 2024-12-14 17:33:57 +01:00
parent 0aeaa5eb22
commit ab780fa48a
5 changed files with 62 additions and 49 deletions

View file

@ -76,6 +76,7 @@ fn pre_expansion_lint<'a>(
|| { || {
rustc_lint::check_ast_node( rustc_lint::check_ast_node(
sess, sess,
None,
features, features,
true, true,
lint_store, lint_store,
@ -310,6 +311,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
let lint_store = unerased_lint_store(tcx.sess); let lint_store = unerased_lint_store(tcx.sess);
rustc_lint::check_ast_node( rustc_lint::check_ast_node(
sess, sess,
Some(tcx),
tcx.features(), tcx.features(),
false, false,
lint_store, lint_store,

View file

@ -20,7 +20,7 @@ use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths}; use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode}; use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode};
use rustc_session::lint::{ use rustc_session::lint::{
BuiltinLintDiag, FutureIncompatibleInfo, Level, Lint, LintBuffer, LintExpectationId, LintId, FutureIncompatibleInfo, Level, Lint, LintBuffer, LintExpectationId, LintId,
}; };
use rustc_session::{LintStoreMarker, Session}; use rustc_session::{LintStoreMarker, Session};
use rustc_span::Span; use rustc_span::Span;
@ -33,8 +33,6 @@ use self::TargetLint::*;
use crate::levels::LintLevelsBuilder; use crate::levels::LintLevelsBuilder;
use crate::passes::{EarlyLintPassObject, LateLintPassObject}; use crate::passes::{EarlyLintPassObject, LateLintPassObject};
mod diagnostics;
type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync; type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync;
type LateLintPassFactory = type LateLintPassFactory =
dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync; dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
@ -511,38 +509,6 @@ pub struct EarlyContext<'a> {
pub buffered: LintBuffer, pub buffered: LintBuffer,
} }
impl EarlyContext<'_> {
/// Emit a lint at the appropriate level, with an associated span and an existing
/// diagnostic.
///
/// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
#[rustc_lint_diagnostics]
pub fn span_lint_with_diagnostics(
&self,
lint: &'static Lint,
span: MultiSpan,
diagnostic: BuiltinLintDiag,
) {
self.opt_span_lint_with_diagnostics(lint, Some(span), diagnostic);
}
/// Emit a lint at the appropriate level, with an optional associated span and an existing
/// diagnostic.
///
/// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
#[rustc_lint_diagnostics]
pub fn opt_span_lint_with_diagnostics(
&self,
lint: &'static Lint,
span: Option<MultiSpan>,
diagnostic: BuiltinLintDiag,
) {
self.opt_span_lint(lint, span, |diag| {
diagnostics::decorate_lint(self.sess(), diagnostic, diag);
});
}
}
pub trait LintContext { pub trait LintContext {
fn sess(&self) -> &Session; fn sess(&self) -> &Session;

View file

@ -8,36 +8,73 @@ use rustc_ast::ptr::P;
use rustc_ast::visit::{self as ast_visit, Visitor, walk_list}; use rustc_ast::visit::{self as ast_visit, Visitor, walk_list};
use rustc_ast::{self as ast, HasAttrs}; use rustc_ast::{self as ast, HasAttrs};
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::MultiSpan;
use rustc_feature::Features; use rustc_feature::Features;
use rustc_middle::ty::RegisteredTools; use rustc_middle::ty::{RegisteredTools, TyCtxt};
use rustc_session::Session; use rustc_session::Session;
use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass}; use rustc_session::lint::{BufferedEarlyLint, BuiltinLintDiag, LintBuffer, LintPass};
use rustc_span::Span; use rustc_span::Span;
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use tracing::debug; use tracing::debug;
use crate::context::{EarlyContext, LintStore}; use crate::Lint;
use crate::context::{EarlyContext, LintContext, LintStore};
use crate::passes::{EarlyLintPass, EarlyLintPassObject}; use crate::passes::{EarlyLintPass, EarlyLintPassObject};
mod diagnostics;
macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({ macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
$cx.pass.$f(&$cx.context, $($args),*); $cx.pass.$f(&$cx.context, $($args),*);
}) } }) }
/// Implements the AST traversal for early lint passes. `T` provides the /// Implements the AST traversal for early lint passes. `T` provides the
/// `check_*` methods. /// `check_*` methods.
pub struct EarlyContextAndPass<'a, T: EarlyLintPass> { pub struct EarlyContextAndPass<'a, 'b, T: EarlyLintPass> {
context: EarlyContext<'a>, context: EarlyContext<'a>,
tcx: Option<TyCtxt<'b>>,
pass: T, pass: T,
} }
impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { impl<T: EarlyLintPass> EarlyContextAndPass<'_, '_, T> {
/// Emit a lint at the appropriate level, with an associated span and an existing
/// diagnostic.
///
/// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
#[rustc_lint_diagnostics]
pub fn span_lint_with_diagnostics(
&self,
lint: &'static Lint,
span: MultiSpan,
diagnostic: BuiltinLintDiag,
) {
self.opt_span_lint_with_diagnostics(lint, Some(span), diagnostic);
}
/// Emit a lint at the appropriate level, with an optional associated span and an existing
/// diagnostic.
///
/// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
#[rustc_lint_diagnostics]
pub fn opt_span_lint_with_diagnostics(
&self,
lint: &'static Lint,
span: Option<MultiSpan>,
diagnostic: BuiltinLintDiag,
) {
self.context.opt_span_lint(lint, span, |diag| {
diagnostics::decorate_lint(self.context.sess(), self.tcx, diagnostic, diag);
});
}
}
impl<'a, 'b, T: EarlyLintPass> EarlyContextAndPass<'a, 'b, T> {
// This always-inlined function is for the hot call site. // This always-inlined function is for the hot call site.
#[inline(always)] #[inline(always)]
#[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::diagnostic_outside_of_impl)]
fn inlined_check_id(&mut self, id: ast::NodeId) { fn inlined_check_id(&mut self, id: ast::NodeId) {
for early_lint in self.context.buffered.take(id) { for early_lint in self.context.buffered.take(id) {
let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint; let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint;
self.context.opt_span_lint_with_diagnostics(lint_id.lint, span, diagnostic); self.opt_span_lint_with_diagnostics(lint_id.lint, span, diagnostic);
} }
} }
@ -67,7 +104,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
} }
} }
impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> { impl<'a, 'b, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, 'b, T> {
fn visit_coroutine_kind(&mut self, coroutine_kind: &'a ast::CoroutineKind) -> Self::Result { fn visit_coroutine_kind(&mut self, coroutine_kind: &'a ast::CoroutineKind) -> Self::Result {
self.check_id(coroutine_kind.closure_id()); self.check_id(coroutine_kind.closure_id());
} }
@ -313,7 +350,7 @@ pub trait EarlyCheckNode<'a>: Copy {
fn attrs<'b>(self) -> &'b [ast::Attribute] fn attrs<'b>(self) -> &'b [ast::Attribute]
where where
'a: 'b; 'a: 'b;
fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>) fn check<'b, 'c, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, 'c, T>)
where where
'a: 'b; 'a: 'b;
} }
@ -328,7 +365,7 @@ impl<'a> EarlyCheckNode<'a> for (&'a ast::Crate, &'a [ast::Attribute]) {
{ {
self.1 self.1
} }
fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>) fn check<'b, 'c, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, 'c, T>)
where where
'a: 'b, 'a: 'b,
{ {
@ -348,7 +385,7 @@ impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [P<ast::
{ {
self.1 self.1
} }
fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>) fn check<'b, 'c, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, 'c, T>)
where where
'a: 'b, 'a: 'b,
{ {
@ -359,6 +396,7 @@ impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [P<ast::
pub fn check_ast_node<'a>( pub fn check_ast_node<'a>(
sess: &Session, sess: &Session,
tcx: Option<TyCtxt<'_>>,
features: &Features, features: &Features,
pre_expansion: bool, pre_expansion: bool,
lint_store: &LintStore, lint_store: &LintStore,
@ -382,22 +420,23 @@ pub fn check_ast_node<'a>(
let passes = let passes =
if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes }; if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes };
if passes.is_empty() { if passes.is_empty() {
check_ast_node_inner(sess, check_node, context, builtin_lints); check_ast_node_inner(sess, tcx, check_node, context, builtin_lints);
} else { } else {
let mut passes: Vec<_> = passes.iter().map(|mk_pass| (mk_pass)()).collect(); let mut passes: Vec<_> = passes.iter().map(|mk_pass| (mk_pass)()).collect();
passes.push(Box::new(builtin_lints)); passes.push(Box::new(builtin_lints));
let pass = RuntimeCombinedEarlyLintPass { passes: &mut passes[..] }; let pass = RuntimeCombinedEarlyLintPass { passes: &mut passes[..] };
check_ast_node_inner(sess, check_node, context, pass); check_ast_node_inner(sess, tcx, check_node, context, pass);
} }
} }
fn check_ast_node_inner<'a, T: EarlyLintPass>( fn check_ast_node_inner<'a, T: EarlyLintPass>(
sess: &Session, sess: &Session,
tcx: Option<TyCtxt<'_>>,
check_node: impl EarlyCheckNode<'a>, check_node: impl EarlyCheckNode<'a>,
context: EarlyContext<'_>, context: EarlyContext<'_>,
pass: T, pass: T,
) { ) {
let mut cx = EarlyContextAndPass { context, pass }; let mut cx = EarlyContextAndPass { context, tcx, pass };
cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx)); cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx));

View file

@ -8,6 +8,7 @@ use rustc_errors::{
Applicability, Diag, DiagArgValue, LintDiagnostic, elided_lifetime_in_path_suggestion, Applicability, Diag, DiagArgValue, LintDiagnostic, elided_lifetime_in_path_suggestion,
}; };
use rustc_middle::middle::stability; use rustc_middle::middle::stability;
use rustc_middle::ty::TyCtxt;
use rustc_session::Session; use rustc_session::Session;
use rustc_session::lint::{BuiltinLintDiag, ElidedLifetimeResolution}; use rustc_session::lint::{BuiltinLintDiag, ElidedLifetimeResolution};
use rustc_span::BytePos; use rustc_span::BytePos;
@ -18,7 +19,12 @@ use crate::lints::{self, ElidedNamedLifetime};
mod check_cfg; mod check_cfg;
pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Diag<'_, ()>) { pub(super) fn decorate_lint(
sess: &Session,
_tcx: Option<TyCtxt<'_>>,
diagnostic: BuiltinLintDiag,
diag: &mut Diag<'_, ()>,
) {
match diagnostic { match diagnostic {
BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => { BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => {
let spans: Vec<_> = content let spans: Vec<_> = content