1use std::cell::Cell;
7use std::slice;
8
9use rustc_ast::BindingMode;
10use rustc_ast::util::parser::ExprPrecedence;
11use rustc_data_structures::fx::FxIndexMap;
12use rustc_data_structures::sync;
13use rustc_data_structures::unord::UnordMap;
14use rustc_errors::{Diag, Diagnostic, LintBuffer, LintDiagnostic, MultiSpan};
15use rustc_feature::Features;
16use rustc_hir::def::Res;
17use rustc_hir::def_id::{CrateNum, DefId};
18use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
19use rustc_hir::{Pat, PatKind};
20use rustc_middle::bug;
21use rustc_middle::lint::LevelAndSource;
22use rustc_middle::middle::privacy::EffectiveVisibilities;
23use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
24use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
25use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode};
26use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintExpectationId, LintId};
27use rustc_session::{DynLintStore, Session};
28use rustc_span::edit_distance::find_best_match_for_names;
29use rustc_span::{Ident, Span, Symbol, sym};
30use tracing::debug;
31use {rustc_abi as abi, rustc_hir as hir};
32
33use self::TargetLint::*;
34use crate::levels::LintLevelsBuilder;
35use crate::passes::{EarlyLintPassObject, LateLintPassObject};
36
37type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync;
38type LateLintPassFactory =
39 dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
40
41pub struct LintStore {
43 lints: Vec<&'static Lint>,
45
46 pub pre_expansion_passes: Vec<Box<EarlyLintPassFactory>>,
53 pub early_passes: Vec<Box<EarlyLintPassFactory>>,
54 pub late_passes: Vec<Box<LateLintPassFactory>>,
55 pub late_module_passes: Vec<Box<LateLintPassFactory>>,
57
58 by_name: UnordMap<String, TargetLint>,
60
61 lint_groups: FxIndexMap<&'static str, LintGroup>,
63}
64
65impl DynLintStore for LintStore {
66 fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = rustc_session::LintGroup> + '_> {
67 Box::new(self.get_lint_groups().map(|(name, lints, is_externally_loaded)| {
68 rustc_session::LintGroup { name, lints, is_externally_loaded }
69 }))
70 }
71}
72
73#[derive(#[automatically_derived]
impl ::core::fmt::Debug for TargetLint {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
TargetLint::Id(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Id",
&__self_0),
TargetLint::Renamed(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f,
"Renamed", __self_0, &__self_1),
TargetLint::Removed(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Removed", &__self_0),
TargetLint::Ignored =>
::core::fmt::Formatter::write_str(f, "Ignored"),
}
}
}Debug)]
75enum TargetLint {
76 Id(LintId),
78
79 Renamed(String, LintId),
81
82 Removed(String),
85
86 Ignored,
91}
92
93struct LintAlias {
94 name: &'static str,
95 silent: bool,
97}
98
99struct LintGroup {
100 lint_ids: Vec<LintId>,
101 is_externally_loaded: bool,
102 depr: Option<LintAlias>,
103}
104
105#[derive(#[automatically_derived]
impl<'a> ::core::fmt::Debug for CheckLintNameResult<'a> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
CheckLintNameResult::Ok(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Ok",
&__self_0),
CheckLintNameResult::NoLint(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "NoLint",
&__self_0),
CheckLintNameResult::NoTool =>
::core::fmt::Formatter::write_str(f, "NoTool"),
CheckLintNameResult::Renamed(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Renamed", &__self_0),
CheckLintNameResult::Removed(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Removed", &__self_0),
CheckLintNameResult::Tool(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f, "Tool",
__self_0, &__self_1),
CheckLintNameResult::MissingTool =>
::core::fmt::Formatter::write_str(f, "MissingTool"),
}
}
}Debug)]
106pub enum CheckLintNameResult<'a> {
107 Ok(&'a [LintId]),
108 NoLint(Option<(Symbol, bool)>),
110 NoTool,
112 Renamed(String),
114 Removed(String),
116
117 Tool(&'a [LintId], Option<String>),
121
122 MissingTool,
126}
127
128impl LintStore {
129 pub fn new() -> LintStore {
130 LintStore {
131 lints: ::alloc::vec::Vec::new()vec![],
132 pre_expansion_passes: ::alloc::vec::Vec::new()vec![],
133 early_passes: ::alloc::vec::Vec::new()vec![],
134 late_passes: ::alloc::vec::Vec::new()vec![],
135 late_module_passes: ::alloc::vec::Vec::new()vec![],
136 by_name: Default::default(),
137 lint_groups: Default::default(),
138 }
139 }
140
141 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
142 &self.lints
143 }
144
145 pub fn get_lint_groups(&self) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> {
146 self.lint_groups
147 .iter()
148 .filter(|(_, LintGroup { depr, .. })| {
149 depr.is_none()
151 })
152 .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
153 (*k, lint_ids.clone(), *is_externally_loaded)
154 })
155 }
156
157 pub fn get_all_group_names(&self) -> impl Iterator<Item = &'static str> {
159 self.lint_groups.keys().copied()
160 }
161
162 pub fn register_early_pass(
163 &mut self,
164 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
165 ) {
166 self.early_passes.push(Box::new(pass));
167 }
168
169 pub fn register_pre_expansion_pass(
176 &mut self,
177 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
178 ) {
179 self.pre_expansion_passes.push(Box::new(pass));
180 }
181
182 pub fn register_late_pass(
183 &mut self,
184 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
185 + 'static
186 + sync::DynSend
187 + sync::DynSync,
188 ) {
189 self.late_passes.push(Box::new(pass));
190 }
191
192 pub fn register_late_mod_pass(
193 &mut self,
194 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
195 + 'static
196 + sync::DynSend
197 + sync::DynSync,
198 ) {
199 self.late_module_passes.push(Box::new(pass));
200 }
201
202 pub fn register_lints(&mut self, lints: &[&'static Lint]) {
204 for lint in lints {
205 self.lints.push(lint);
206
207 let id = LintId::of(lint);
208 if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
209 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
lint.name_lower()))bug!("duplicate specification of lint {}", lint.name_lower())
210 }
211
212 if let Some(FutureIncompatibleInfo { reason, .. }) = lint.future_incompatible {
213 if let Some(edition) = reason.edition() {
214 self.lint_groups
215 .entry(edition.lint_name())
216 .or_insert(LintGroup {
217 lint_ids: ::alloc::vec::Vec::new()vec![],
218 is_externally_loaded: lint.is_externally_loaded,
219 depr: None,
220 })
221 .lint_ids
222 .push(id);
223 } else {
224 self.lint_groups
228 .entry("future_incompatible")
229 .or_insert(LintGroup {
230 lint_ids: ::alloc::vec::Vec::new()vec![],
231 is_externally_loaded: lint.is_externally_loaded,
232 depr: None,
233 })
234 .lint_ids
235 .push(id);
236 }
237 }
238 }
239 }
240
241 fn insert_group(&mut self, name: &'static str, group: LintGroup) {
242 let previous = self.lint_groups.insert(name, group);
243 if previous.is_some() {
244 ::rustc_middle::util::bug::bug_fmt(format_args!("group {0:?} already exists",
name));bug!("group {name:?} already exists");
245 }
246 }
247
248 pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) {
249 let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else {
250 ::rustc_middle::util::bug::bug_fmt(format_args!("group alias {0:?} points to unregistered group {1:?}",
alias, group_name))bug!("group alias {alias:?} points to unregistered group {group_name:?}")
251 };
252
253 self.insert_group(
254 alias,
255 LintGroup {
256 lint_ids: lint_ids.clone(),
257 is_externally_loaded: false,
258 depr: Some(LintAlias { name: group_name, silent: true }),
259 },
260 );
261 }
262
263 pub fn register_group(
264 &mut self,
265 is_externally_loaded: bool,
266 name: &'static str,
267 deprecated_name: Option<&'static str>,
268 to: Vec<LintId>,
269 ) {
270 if let Some(deprecated) = deprecated_name {
271 self.insert_group(
272 deprecated,
273 LintGroup {
274 lint_ids: to.clone(),
275 is_externally_loaded,
276 depr: Some(LintAlias { name, silent: false }),
277 },
278 );
279 }
280 self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None });
281 }
282
283 #[track_caller]
287 pub fn register_ignored(&mut self, name: &str) {
288 if self.by_name.insert(name.to_string(), Ignored).is_some() {
289 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
name));bug!("duplicate specification of lint {}", name);
290 }
291 }
292
293 #[track_caller]
295 pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
296 let Some(&Id(target)) = self.by_name.get(new_name) else {
297 ::rustc_middle::util::bug::bug_fmt(format_args!("invalid lint renaming of {0} to {1}",
old_name, new_name));bug!("invalid lint renaming of {} to {}", old_name, new_name);
298 };
299 self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
300 }
301
302 pub fn register_removed(&mut self, name: &str, reason: &str) {
303 self.by_name.insert(name.into(), Removed(reason.into()));
304 }
305
306 pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
307 match self.by_name.get(lint_name) {
308 Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
309 Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)),
310 Some(Removed(_)) => None,
311 Some(Ignored) => Some(&[]),
312 None => match self.lint_groups.get(lint_name) {
313 Some(LintGroup { lint_ids, .. }) => Some(lint_ids),
314 None => None,
315 },
316 }
317 }
318
319 pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
321 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/context.rs:321",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(321u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::context"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("is_lint_group(lint_name={0:?}, lint_groups={1:?})",
lint_name, self.lint_groups.keys().collect::<Vec<_>>()) as
&dyn Value))])
});
} else { ; }
};debug!(
322 "is_lint_group(lint_name={:?}, lint_groups={:?})",
323 lint_name,
324 self.lint_groups.keys().collect::<Vec<_>>()
325 );
326 let lint_name_str = lint_name.as_str();
327 self.lint_groups.contains_key(lint_name_str) || {
328 let warnings_name_str = crate::WARNINGS.name_lower();
329 lint_name_str == warnings_name_str
330 }
331 }
332
333 pub fn check_lint_name(
341 &self,
342 lint_name: &str,
343 tool_name: Option<Symbol>,
344 registered_tools: &RegisteredTools,
345 ) -> CheckLintNameResult<'_> {
346 if let Some(tool_name) = tool_name {
347 if tool_name != sym::rustc
349 && tool_name != sym::rustdoc
350 && !registered_tools.contains(&Ident::with_dummy_span(tool_name))
351 {
352 return CheckLintNameResult::NoTool;
353 }
354 }
355
356 let complete_name = if let Some(tool_name) = tool_name {
357 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}")
358 } else {
359 lint_name.to_string()
360 };
361 if let Some(tool_name) = tool_name {
363 match self.by_name.get(&complete_name) {
364 None => match self.lint_groups.get(&*complete_name) {
365 None => {
367 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/context.rs:369",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(369u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::context"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("lints={0:?}",
self.by_name) as &dyn Value))])
});
} else { ; }
};debug!("lints={:?}", self.by_name);
370 let tool_prefix = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::", tool_name))
})format!("{tool_name}::");
371
372 return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
373 self.no_lint_suggestion(&complete_name, tool_name.as_str())
374 } else {
375 CheckLintNameResult::MissingTool
378 };
379 }
380 Some(LintGroup { lint_ids, depr, .. }) => {
381 return if let &Some(LintAlias { name, silent: false }) = depr {
382 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
383 } else {
384 CheckLintNameResult::Tool(lint_ids, None)
385 };
386 }
387 },
388 Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
389 _ => {}
392 }
393 }
394 match self.by_name.get(&complete_name) {
395 Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
396 Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
397 None => match self.lint_groups.get(&*complete_name) {
398 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
401 Some(LintGroup { lint_ids, depr, .. }) => {
402 if let &Some(LintAlias { name, silent: false }) = depr {
404 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
405 } else {
406 CheckLintNameResult::Ok(lint_ids)
407 }
408 }
409 },
410 Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
411 Some(&Ignored) => CheckLintNameResult::Ok(&[]),
412 }
413 }
414
415 fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
416 let name_lower = lint_name.to_lowercase();
417
418 if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() {
419 return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
421 }
422
423 #[allow(rustc::potential_query_instability)]
429 let mut groups: Vec<_> = self
430 .lint_groups
431 .iter()
432 .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k))
433 .collect();
434 groups.sort();
435 let groups = groups.iter().map(|k| Symbol::intern(k));
436 let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
437 let names: Vec<Symbol> = groups.chain(lints).collect();
438 let mut lookups = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[Symbol::intern(&name_lower)]))vec![Symbol::intern(&name_lower)];
439 if let Some(stripped) = name_lower.split("::").last() {
440 lookups.push(Symbol::intern(stripped));
441 }
442 let res = find_best_match_for_names(&names, &lookups, None);
443 let is_rustc = res.map_or_else(
444 || false,
445 |s| name_lower.contains("::") && !s.as_str().starts_with(tool_name),
446 );
447 let suggestion = res.map(|s| (s, is_rustc));
448 CheckLintNameResult::NoLint(suggestion)
449 }
450
451 fn check_tool_name_for_backwards_compat(
452 &self,
453 lint_name: &str,
454 tool_name: &str,
455 ) -> CheckLintNameResult<'_> {
456 let complete_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}");
457 match self.by_name.get(&complete_name) {
458 None => match self.lint_groups.get(&*complete_name) {
459 None => self.no_lint_suggestion(lint_name, tool_name),
461 Some(LintGroup { lint_ids, .. }) => {
462 CheckLintNameResult::Tool(lint_ids, Some(complete_name))
463 }
464 },
465 Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)),
466 Some(other) => {
467 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/context.rs:467",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(467u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::context"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("got renamed lint {0:?}",
other) as &dyn Value))])
});
} else { ; }
};debug!("got renamed lint {:?}", other);
468 CheckLintNameResult::NoLint(None)
469 }
470 }
471 }
472}
473
474pub struct LateContext<'tcx> {
476 pub tcx: TyCtxt<'tcx>,
478
479 pub enclosing_body: Option<hir::BodyId>,
481
482 pub(super) cached_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
487
488 pub param_env: ty::ParamEnv<'tcx>,
490
491 pub effective_visibilities: &'tcx EffectiveVisibilities,
493
494 pub last_node_with_lint_attrs: hir::HirId,
495
496 pub generics: Option<&'tcx hir::Generics<'tcx>>,
498
499 pub only_module: bool,
501}
502
503pub struct EarlyContext<'a> {
505 pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>,
506 pub buffered: LintBuffer,
507}
508
509pub trait LintContext {
510 fn sess(&self) -> &Session;
511
512 #[track_caller]
518 fn opt_span_lint<S: Into<MultiSpan>>(
519 &self,
520 lint: &'static Lint,
521 span: Option<S>,
522 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
523 );
524
525 #[track_caller]
531 fn opt_span_diag_lint<S: Into<MultiSpan>>(
532 &self,
533 lint: &'static Lint,
534 span: Option<S>,
535 decorate: impl for<'a> Diagnostic<'a, ()>,
536 );
537
538 fn emit_span_lint<S: Into<MultiSpan>>(
541 &self,
542 lint: &'static Lint,
543 span: S,
544 decorator: impl for<'a> Diagnostic<'a, ()>,
545 ) {
546 self.opt_span_diag_lint(lint, Some(span), decorator);
547 }
548
549 fn emit_span_lint_lazy<S: Into<MultiSpan>, L: for<'a> LintDiagnostic<'a, ()>>(
552 &self,
553 lint: &'static Lint,
554 span: S,
555 decorator: impl FnOnce() -> L,
556 ) {
557 self.opt_span_lint(lint, Some(span), |lint| {
558 let decorator = decorator();
559 decorator.decorate_lint(lint);
560 });
561 }
562
563 #[track_caller]
567 fn span_lint<S: Into<MultiSpan>>(
568 &self,
569 lint: &'static Lint,
570 span: S,
571 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
572 ) {
573 self.opt_span_lint(lint, Some(span), decorate);
574 }
575
576 fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> LintDiagnostic<'a, ()>) {
579 self.opt_span_lint(lint, None as Option<Span>, |lint| {
580 decorator.decorate_lint(lint);
581 });
582 }
583
584 fn emit_diag_lint(&self, lint: &'static Lint, decorator: impl for<'a> Diagnostic<'a, ()>) {
587 self.opt_span_diag_lint(lint, None as Option<Span>, decorator);
588 }
589
590 fn lint(&self, lint: &'static Lint, decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>)) {
594 self.opt_span_lint(lint, None as Option<Span>, decorate);
595 }
596
597 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource;
599
600 fn fulfill_expectation(&self, expectation: LintExpectationId) {
608 self.sess()
613 .dcx()
614 .struct_expect(
615 "this is a dummy diagnostic, to submit and store an expectation",
616 expectation,
617 )
618 .emit();
619 }
620}
621
622impl<'a> EarlyContext<'a> {
623 pub(crate) fn new(
624 sess: &'a Session,
625 features: &'a Features,
626 lint_added_lints: bool,
627 lint_store: &'a LintStore,
628 registered_tools: &'a RegisteredTools,
629 buffered: LintBuffer,
630 ) -> EarlyContext<'a> {
631 EarlyContext {
632 builder: LintLevelsBuilder::new(
633 sess,
634 features,
635 lint_added_lints,
636 lint_store,
637 registered_tools,
638 ),
639 buffered,
640 }
641 }
642}
643
644impl<'tcx> LintContext for LateContext<'tcx> {
645 fn sess(&self) -> &Session {
647 self.tcx.sess
648 }
649
650 fn opt_span_lint<S: Into<MultiSpan>>(
651 &self,
652 lint: &'static Lint,
653 span: Option<S>,
654 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
655 ) {
656 let hir_id = self.last_node_with_lint_attrs;
657
658 match span {
659 Some(s) => self.tcx.node_span_lint(lint, hir_id, s, decorate),
660 None => self.tcx.node_lint(lint, hir_id, decorate),
661 }
662 }
663
664 fn opt_span_diag_lint<S: Into<MultiSpan>>(
665 &self,
666 lint: &'static Lint,
667 span: Option<S>,
668 decorate: impl for<'a> Diagnostic<'a, ()>,
669 ) {
670 let hir_id = self.last_node_with_lint_attrs;
671
672 match span {
673 Some(s) => self.tcx.emit_node_span_lint(lint, hir_id, s, decorate),
674 None => self.tcx.emit_node_lint(lint, hir_id, decorate),
675 }
676 }
677
678 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
679 self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs)
680 }
681}
682
683impl LintContext for EarlyContext<'_> {
684 fn sess(&self) -> &Session {
686 self.builder.sess()
687 }
688
689 fn opt_span_lint<S: Into<MultiSpan>>(
690 &self,
691 lint: &'static Lint,
692 span: Option<S>,
693 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
694 ) {
695 self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorate)
696 }
697
698 fn opt_span_diag_lint<S: Into<MultiSpan>>(
699 &self,
700 lint: &'static Lint,
701 span: Option<S>,
702 decorator: impl for<'a> Diagnostic<'a, ()>,
703 ) {
704 self.builder.opt_span_diag_lint(lint, span.map(|s| s.into()), decorator)
705 }
706
707 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
708 self.builder.lint_level(lint)
709 }
710}
711
712impl<'tcx> LateContext<'tcx> {
713 pub fn typing_mode(&self) -> TypingMode<'tcx> {
716 TypingMode::non_body_analysis()
719 }
720
721 pub fn typing_env(&self) -> TypingEnv<'tcx> {
722 TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
723 }
724
725 pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
726 self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
727 }
728
729 pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
730 self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
731 }
732
733 pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
736 self.cached_typeck_results.get().or_else(|| {
737 self.enclosing_body.map(|body| {
738 let typeck_results = self.tcx.typeck_body(body);
739 self.cached_typeck_results.set(Some(typeck_results));
740 typeck_results
741 })
742 })
743 }
744
745 #[track_caller]
749 pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
750 self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body")
751 }
752
753 pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
757 match *qpath {
758 hir::QPath::Resolved(_, path) => path.res,
759 hir::QPath::TypeRelative(..) => self
760 .maybe_typeck_results()
761 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
762 .or_else(|| {
763 self.tcx
764 .has_typeck_results(id.owner.def_id)
765 .then(|| self.tcx.typeck(id.owner.def_id))
766 })
767 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
768 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
769 }
770 }
771
772 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
792 struct LintPathPrinter<'tcx> {
793 tcx: TyCtxt<'tcx>,
794 path: Vec<Symbol>,
795 }
796
797 impl<'tcx> Printer<'tcx> for LintPathPrinter<'tcx> {
798 fn tcx(&self) -> TyCtxt<'tcx> {
799 self.tcx
800 }
801
802 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
803 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
805
806 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
807 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
809
810 fn print_dyn_existential(
811 &mut self,
812 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
813 ) -> Result<(), PrintError> {
814 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
816
817 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
818 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
820
821 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
822 self.path = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[self.tcx.crate_name(cnum)]))vec![self.tcx.crate_name(cnum)];
823 Ok(())
824 }
825
826 fn print_path_with_qualified(
827 &mut self,
828 self_ty: Ty<'tcx>,
829 trait_ref: Option<ty::TraitRef<'tcx>>,
830 ) -> Result<(), PrintError> {
831 if trait_ref.is_none()
832 && let ty::Adt(def, args) = self_ty.kind()
833 {
834 return self.print_def_path(def.did(), args);
835 }
836
837 {
let _guard = NoTrimmedGuard::new();
{
self.path =
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[match trait_ref {
Some(trait_ref) =>
Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", trait_ref))
})),
None =>
Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{0}>", self_ty))
})),
}]));
Ok(())
}
}with_no_trimmed_paths!({
839 self.path = vec![match trait_ref {
840 Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
841 None => Symbol::intern(&format!("<{self_ty}>")),
842 }];
843 Ok(())
844 })
845 }
846
847 fn print_path_with_impl(
848 &mut self,
849 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
850 self_ty: Ty<'tcx>,
851 trait_ref: Option<ty::TraitRef<'tcx>>,
852 ) -> Result<(), PrintError> {
853 print_prefix(self)?;
854
855 self.path.push(match trait_ref {
857 Some(trait_ref) => {
858 {
let _guard = NoTrimmedGuard::new();
Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<impl {0} for {1}>",
trait_ref.print_only_trait_path(), self_ty))
}))
}with_no_trimmed_paths!(Symbol::intern(&format!(
859 "<impl {} for {}>",
860 trait_ref.print_only_trait_path(),
861 self_ty
862 )))
863 }
864 None => {
865 {
let _guard = NoTrimmedGuard::new();
Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<impl {0}>", self_ty))
}))
}with_no_trimmed_paths!(Symbol::intern(&format!("<impl {self_ty}>")))
866 }
867 });
868
869 Ok(())
870 }
871
872 fn print_path_with_simple(
873 &mut self,
874 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
875 disambiguated_data: &DisambiguatedDefPathData,
876 ) -> Result<(), PrintError> {
877 print_prefix(self)?;
878
879 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
881 return Ok(());
882 }
883
884 self.path.push(match disambiguated_data.data.get_opt_name() {
885 Some(sym) => sym,
886 None => Symbol::intern(&disambiguated_data.data.to_string()),
887 });
888 Ok(())
889 }
890
891 fn print_path_with_generic_args(
892 &mut self,
893 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
894 _args: &[GenericArg<'tcx>],
895 ) -> Result<(), PrintError> {
896 print_prefix(self)
897 }
898 }
899
900 let mut p = LintPathPrinter { tcx: self.tcx, path: ::alloc::vec::Vec::new()vec![] };
901 p.print_def_path(def_id, &[]).unwrap();
902 p.path
903 }
904
905 pub fn get_associated_type(
908 &self,
909 self_ty: Ty<'tcx>,
910 trait_id: DefId,
911 name: Symbol,
912 ) -> Option<Ty<'tcx>> {
913 let tcx = self.tcx;
914 tcx.associated_items(trait_id)
915 .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
916 .and_then(|assoc| {
917 let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
918 tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()
919 })
920 }
921
922 pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
926 let has_attr = |id: hir::HirId| -> bool {
927 for attr in self.tcx.hir_attrs(id) {
928 if attr.span().desugaring_kind().is_none() {
929 return true;
930 }
931 }
932 false
933 };
934 expr.precedence(&has_attr)
935 }
936
937 pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
953 expr = expr.peel_blocks();
954
955 while let hir::ExprKind::Path(ref qpath) = expr.kind
956 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
957 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
958 _ => None,
959 }
960 && let Some(init) = match parent_node {
961 hir::Node::Expr(expr) => Some(expr),
962 hir::Node::LetStmt(hir::LetStmt {
963 init,
964 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
966 ..
967 }) => *init,
968 _ => None,
969 }
970 {
971 expr = init.peel_blocks();
972 }
973 expr
974 }
975
976 pub fn expr_or_init_with_outside_body<'a>(
999 &self,
1000 mut expr: &'a hir::Expr<'tcx>,
1001 ) -> &'a hir::Expr<'tcx> {
1002 expr = expr.peel_blocks();
1003
1004 while let hir::ExprKind::Path(ref qpath) = expr.kind
1005 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
1006 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
1007 Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
1008 _ => None,
1009 }
1010 && let Some(init) = match parent_node {
1011 hir::Node::Expr(expr) => Some(expr),
1012 hir::Node::LetStmt(hir::LetStmt {
1013 init,
1014 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
1016 ..
1017 }) => *init,
1018 hir::Node::Item(item) => match item.kind {
1019 hir::ItemKind::Const(.., hir::ConstItemRhs::Body(body_id))
1021 | hir::ItemKind::Static(.., body_id) => Some(self.tcx.hir_body(body_id).value),
1022 _ => None,
1023 },
1024 _ => None,
1025 }
1026 {
1027 expr = init.peel_blocks();
1028 }
1029 expr
1030 }
1031}
1032
1033impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
1034 #[inline]
1035 fn data_layout(&self) -> &abi::TargetDataLayout {
1036 &self.tcx.data_layout
1037 }
1038}
1039
1040impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
1041 #[inline]
1042 fn tcx(&self) -> TyCtxt<'tcx> {
1043 self.tcx
1044 }
1045}
1046
1047impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
1048 #[inline]
1049 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
1050 self.typing_env()
1051 }
1052}
1053
1054impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
1055 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
1056
1057 #[inline]
1058 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
1059 err
1060 }
1061}