mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Make DecorateDiagCompat::Dynamic take an Any reference allowing to downcast to Session
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
use std::any::Any;
|
||||
|
||||
/// This module provides types and traits for buffering lints until later in compilation.
|
||||
use rustc_ast::node_id::NodeId;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
@@ -10,9 +12,11 @@
|
||||
/// We can't implement `Diagnostic` for `BuiltinLintDiag`, because decorating some of its
|
||||
/// variants requires types we don't have yet. So, handle that case separately.
|
||||
pub enum DecorateDiagCompat {
|
||||
/// The third argument of the closure is a `Session`. However, due to the dependency tree,
|
||||
/// we don't have access to `rustc_session` here, so we downcast it when needed.
|
||||
Dynamic(
|
||||
Box<
|
||||
dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()>
|
||||
dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()>
|
||||
+ DynSync
|
||||
+ DynSend
|
||||
+ 'static,
|
||||
@@ -30,7 +34,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
impl<D: for<'a> Diagnostic<'a, ()> + DynSync + DynSend + 'static> From<D> for DecorateDiagCompat {
|
||||
#[inline]
|
||||
fn from(d: D) -> Self {
|
||||
Self::Dynamic(Box::new(|dcx, level| d.into_diag(dcx, level)))
|
||||
Self::Dynamic(Box::new(|dcx, level, _| d.into_diag(dcx, level)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +101,26 @@ pub fn dyn_buffer_lint<
|
||||
node_id: NodeId,
|
||||
span: impl Into<MultiSpan>,
|
||||
callback: F,
|
||||
) {
|
||||
self.add_early_lint(BufferedEarlyLint {
|
||||
lint_id: LintId::of(lint),
|
||||
node_id,
|
||||
span: Some(span.into()),
|
||||
diagnostic: DecorateDiagCompat::Dynamic(Box::new(|dcx, level, _| callback(dcx, level))),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn dyn_buffer_lint_any<
|
||||
F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()>
|
||||
+ DynSend
|
||||
+ DynSync
|
||||
+ 'static,
|
||||
>(
|
||||
&mut self,
|
||||
lint: &'static Lint,
|
||||
node_id: NodeId,
|
||||
span: impl Into<MultiSpan>,
|
||||
callback: F,
|
||||
) {
|
||||
self.add_early_lint(BufferedEarlyLint {
|
||||
lint_id: LintId::of(lint),
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
use std::path::PathBuf;
|
||||
use std::thread::panicking;
|
||||
|
||||
use rustc_data_structures::sync::{DynSend, DynSync};
|
||||
use rustc_error_messages::{DiagArgMap, DiagArgName, DiagArgValue, IntoDiagArg};
|
||||
use rustc_lint_defs::{Applicability, LintExpectationId};
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
@@ -119,16 +118,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Diagnostic<'a, ()>
|
||||
for Box<
|
||||
dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSync + DynSend + 'static,
|
||||
>
|
||||
{
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
self(dcx, level)
|
||||
}
|
||||
}
|
||||
|
||||
/// Type used to emit diagnostic through a closure instead of implementing the `Diagnostic` trait.
|
||||
pub struct DiagDecorator<F: FnOnce(&mut Diag<'_, ()>)>(pub F);
|
||||
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
use rustc_span::{DUMMY_SP, Ident, Span};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::DecorateBuiltinLint;
|
||||
use crate::context::{EarlyContext, LintContext, LintStore};
|
||||
use crate::passes::{EarlyLintPass, EarlyLintPassObject};
|
||||
use crate::{DecorateBuiltinLint, DiagAndSess};
|
||||
|
||||
pub(super) mod diagnostics;
|
||||
|
||||
@@ -49,8 +49,12 @@ fn check_id(&mut self, id: ast::NodeId) {
|
||||
},
|
||||
);
|
||||
}
|
||||
DecorateDiagCompat::Dynamic(d) => {
|
||||
self.context.opt_span_lint(lint_id.lint, span, d);
|
||||
DecorateDiagCompat::Dynamic(callback) => {
|
||||
self.context.opt_span_lint(
|
||||
lint_id.lint,
|
||||
span,
|
||||
DiagAndSess { callback, sess: self.context.sess() },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use std::any::Any;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc_data_structures::sync::DynSend;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level,
|
||||
elided_lifetime_in_path_suggestion,
|
||||
@@ -13,6 +15,19 @@
|
||||
|
||||
mod check_cfg;
|
||||
|
||||
pub struct DiagAndSess<'sess> {
|
||||
pub callback: Box<
|
||||
dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level, &dyn Any) -> Diag<'b, ()> + DynSend + 'static,
|
||||
>,
|
||||
pub sess: &'sess Session,
|
||||
}
|
||||
|
||||
impl<'a> Diagnostic<'a, ()> for DiagAndSess<'_> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
(self.callback)(dcx, level, self.sess)
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a diagnostic struct that will decorate a `BuiltinLintDiag`
|
||||
/// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed.
|
||||
pub struct DecorateBuiltinLint<'sess, 'tcx> {
|
||||
|
||||
@@ -509,22 +509,26 @@ pub(crate) fn lint_if_path_starts_with_module(
|
||||
return;
|
||||
}
|
||||
|
||||
let (replacement, applicability) =
|
||||
match self.tcx.sess.source_map().span_to_snippet(root_span) {
|
||||
Ok(ref s) => {
|
||||
// FIXME(Manishearth) ideally the emitting code
|
||||
// can tell us whether or not this is global
|
||||
let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" };
|
||||
|
||||
(format!("crate{opt_colon}{s}"), Applicability::MachineApplicable)
|
||||
}
|
||||
Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders),
|
||||
};
|
||||
self.lint_buffer.dyn_buffer_lint(
|
||||
self.lint_buffer.dyn_buffer_lint_any(
|
||||
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
|
||||
node_id,
|
||||
root_span,
|
||||
move |dcx, level| {
|
||||
move |dcx, level, sess| {
|
||||
let (replacement, applicability) = match sess
|
||||
.downcast_ref::<Session>()
|
||||
.expect("expected a `Session`")
|
||||
.source_map()
|
||||
.span_to_snippet(root_span)
|
||||
{
|
||||
Ok(ref s) => {
|
||||
// FIXME(Manishearth) ideally the emitting code
|
||||
// can tell us whether or not this is global
|
||||
let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" };
|
||||
|
||||
(format!("crate{opt_colon}{s}"), Applicability::MachineApplicable)
|
||||
}
|
||||
Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders),
|
||||
};
|
||||
errors::AbsPathWithModule {
|
||||
sugg: errors::AbsPathWithModuleSugg {
|
||||
span: root_span,
|
||||
|
||||
@@ -3641,49 +3641,48 @@ pub(crate) fn maybe_report_lifetime_uses(
|
||||
match use_set {
|
||||
Some(LifetimeUseSet::Many) => {}
|
||||
Some(LifetimeUseSet::One { use_span, use_ctxt }) => {
|
||||
debug!(?param.ident, ?param.ident.span, ?use_span);
|
||||
|
||||
let elidable = matches!(use_ctxt, LifetimeCtxt::Ref);
|
||||
let param_ident = param.ident;
|
||||
let deletion_span =
|
||||
if param.bounds.is_empty() { deletion_span() } else { None };
|
||||
|
||||
let tcx = self.r.tcx;
|
||||
let param_ident = param.ident;
|
||||
let sugg_data = deletion_span.map(|deletion_span| {
|
||||
if elidable {
|
||||
let use_span =
|
||||
tcx.sess.source_map().span_extend_while_whitespace(use_span);
|
||||
(deletion_span, use_span, String::new())
|
||||
} else {
|
||||
(deletion_span, use_span, "'_".to_owned())
|
||||
}
|
||||
});
|
||||
self.r.lint_buffer.dyn_buffer_lint(
|
||||
self.r.lint_buffer.dyn_buffer_lint_any(
|
||||
lint::builtin::SINGLE_USE_LIFETIMES,
|
||||
param.id,
|
||||
param.ident.span,
|
||||
move |dcx, level| {
|
||||
let suggestion =
|
||||
sugg_data.map(|(deletion_span, use_span, replace_lt)| {
|
||||
// issue 107998 for the case such as a wrong function pointer type
|
||||
// `deletion_span` is empty and there is no need to report lifetime uses here
|
||||
let deletion_span = if deletion_span.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(deletion_span)
|
||||
};
|
||||
errors::SingleUseLifetimeSugg {
|
||||
deletion_span,
|
||||
use_span,
|
||||
replace_lt,
|
||||
}
|
||||
});
|
||||
let param_span = param_ident.span;
|
||||
debug!(?param_span, ?use_span, ?deletion_span);
|
||||
param_ident.span,
|
||||
move |dcx, level, sess| {
|
||||
debug!(?param_ident, ?param_ident.span, ?use_span);
|
||||
|
||||
let elidable = matches!(use_ctxt, LifetimeCtxt::Ref);
|
||||
let suggestion = if let Some(deletion_span) = deletion_span {
|
||||
let (use_span, replace_lt) = if elidable {
|
||||
let use_span = sess
|
||||
.downcast_ref::<Session>()
|
||||
.expect("expected a `Session`")
|
||||
.source_map()
|
||||
.span_extend_while_whitespace(use_span);
|
||||
(use_span, String::new())
|
||||
} else {
|
||||
(use_span, "'_".to_owned())
|
||||
};
|
||||
debug!(?deletion_span, ?use_span);
|
||||
|
||||
// issue 107998 for the case such as a wrong function pointer type
|
||||
// `deletion_span` is empty and there is no need to report lifetime uses here
|
||||
let deletion_span = if deletion_span.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(deletion_span)
|
||||
};
|
||||
Some(errors::SingleUseLifetimeSugg {
|
||||
deletion_span,
|
||||
use_span,
|
||||
replace_lt,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
errors::SingleUseLifetime {
|
||||
suggestion,
|
||||
param_span,
|
||||
param_span: param_ident.span,
|
||||
use_span,
|
||||
ident: param_ident,
|
||||
}
|
||||
|
||||
@@ -344,7 +344,7 @@ pub fn dyn_buffer_lint<
|
||||
lint,
|
||||
Some(span.into()),
|
||||
node_id,
|
||||
DecorateDiagCompat::Dynamic(Box::new(callback)),
|
||||
DecorateDiagCompat::Dynamic(Box::new(|dcx, level, _| callback(dcx, level))),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user