1use std::cell::Cell;
7use std::slice;
8
9use rustc_abi as abi;
10use rustc_ast::BindingMode;
11use rustc_ast::util::parser::ExprPrecedence;
12use rustc_data_structures::fx::FxIndexMap;
13use rustc_data_structures::sync;
14use rustc_data_structures::unord::UnordMap;
15use rustc_errors::{Diagnostic, LintBuffer, MultiSpan};
16use rustc_feature::Features;
17use rustc_hir as hir;
18use rustc_hir::def::Res;
19use rustc_hir::def_id::{CrateNum, DefId};
20use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
21use rustc_hir::{Pat, PatKind};
22use rustc_middle::bug;
23use rustc_middle::lint::{LevelSpec, StableLevelSpec, UnstableLevelSpec};
24use rustc_middle::middle::privacy::EffectiveVisibilities;
25use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
26use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
27use rustc_middle::ty::{
28 self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode, Unnormalized,
29};
30use rustc_session::lint::{
31 FutureIncompatibleInfo, Lint, LintExpectationId, LintId, StableLintExpectationId,
32 UnstableLintExpectationId,
33};
34use rustc_session::{DynLintStore, Session};
35use rustc_span::edit_distance::find_best_match_for_names;
36use rustc_span::{Ident, Span, Symbol, sym};
37use tracing::debug;
38
39use self::TargetLint::*;
40use crate::levels::LintLevelsBuilder;
41use crate::passes::{EarlyLintPassObject, LateLintPassObject};
42
43type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync;
44type LateLintPassFactory =
45 dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
46
47pub struct LintStore {
49 lints: Vec<&'static Lint>,
51
52 pub pre_expansion_passes: Vec<Box<EarlyLintPassFactory>>,
59 pub early_passes: Vec<Box<EarlyLintPassFactory>>,
60 pub late_passes: Vec<Box<LateLintPassFactory>>,
61 pub late_module_passes: Vec<Box<LateLintPassFactory>>,
63
64 by_name: UnordMap<String, TargetLint>,
66
67 lint_groups: FxIndexMap<&'static str, LintGroup>,
69}
70
71impl DynLintStore for LintStore {
72 fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = rustc_session::LintGroup> + '_> {
73 Box::new(self.get_lint_groups().map(|(name, lints, is_externally_loaded)| {
74 rustc_session::LintGroup { name, lints, is_externally_loaded }
75 }))
76 }
77}
78
79#[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)]
81enum TargetLint {
82 Id(LintId),
84
85 Renamed(String, LintId),
87
88 Removed(String),
91
92 Ignored,
97}
98
99struct LintAlias {
100 name: &'static str,
101 silent: bool,
103}
104
105struct LintGroup {
106 lint_ids: Vec<LintId>,
107 is_externally_loaded: bool,
108 depr: Option<LintAlias>,
109}
110
111#[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)]
112pub enum CheckLintNameResult<'a> {
113 Ok(&'a [LintId]),
114 NoLint(Option<(Symbol, bool)>),
116 NoTool,
118 Renamed(String),
120 Removed(String),
122
123 Tool(&'a [LintId], Option<String>),
127
128 MissingTool,
132}
133
134impl LintStore {
135 pub fn new() -> LintStore {
136 LintStore {
137 lints: ::alloc::vec::Vec::new()vec![],
138 pre_expansion_passes: ::alloc::vec::Vec::new()vec![],
139 early_passes: ::alloc::vec::Vec::new()vec![],
140 late_passes: ::alloc::vec::Vec::new()vec![],
141 late_module_passes: ::alloc::vec::Vec::new()vec![],
142 by_name: Default::default(),
143 lint_groups: Default::default(),
144 }
145 }
146
147 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
148 &self.lints
149 }
150
151 pub fn get_lint_groups(&self) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> {
152 self.lint_groups
153 .iter()
154 .filter(|(_, LintGroup { depr, .. })| {
155 depr.is_none()
157 })
158 .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
159 (*k, lint_ids.clone(), *is_externally_loaded)
160 })
161 }
162
163 pub fn get_all_group_names(&self) -> impl Iterator<Item = &'static str> {
165 self.lint_groups.keys().copied()
166 }
167
168 pub fn register_early_pass(
169 &mut self,
170 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
171 ) {
172 self.early_passes.push(Box::new(pass));
173 }
174
175 pub fn register_pre_expansion_pass(
182 &mut self,
183 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
184 ) {
185 self.pre_expansion_passes.push(Box::new(pass));
186 }
187
188 pub fn register_late_pass(
189 &mut self,
190 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
191 + 'static
192 + sync::DynSend
193 + sync::DynSync,
194 ) {
195 self.late_passes.push(Box::new(pass));
196 }
197
198 pub fn register_late_mod_pass(
199 &mut self,
200 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
201 + 'static
202 + sync::DynSend
203 + sync::DynSync,
204 ) {
205 self.late_module_passes.push(Box::new(pass));
206 }
207
208 pub fn register_lints(&mut self, lints: &[&'static Lint]) {
210 for lint in lints {
211 self.lints.push(lint);
212
213 let id = LintId::of(lint);
214 if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
215 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
lint.name_lower()))bug!("duplicate specification of lint {}", lint.name_lower())
216 }
217
218 if let Some(FutureIncompatibleInfo { reason, .. }) = lint.future_incompatible {
219 if let Some(edition) = reason.edition() {
220 self.lint_groups
221 .entry(edition.lint_name())
222 .or_insert(LintGroup {
223 lint_ids: ::alloc::vec::Vec::new()vec![],
224 is_externally_loaded: lint.is_externally_loaded,
225 depr: None,
226 })
227 .lint_ids
228 .push(id);
229 } else {
230 self.lint_groups
234 .entry("future_incompatible")
235 .or_insert(LintGroup {
236 lint_ids: ::alloc::vec::Vec::new()vec![],
237 is_externally_loaded: lint.is_externally_loaded,
238 depr: None,
239 })
240 .lint_ids
241 .push(id);
242 }
243 }
244 }
245 }
246
247 fn insert_group(&mut self, name: &'static str, group: LintGroup) {
248 let previous = self.lint_groups.insert(name, group);
249 if previous.is_some() {
250 ::rustc_middle::util::bug::bug_fmt(format_args!("group {0:?} already exists",
name));bug!("group {name:?} already exists");
251 }
252 }
253
254 pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) {
255 let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else {
256 ::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:?}")
257 };
258
259 self.insert_group(
260 alias,
261 LintGroup {
262 lint_ids: lint_ids.clone(),
263 is_externally_loaded: false,
264 depr: Some(LintAlias { name: group_name, silent: true }),
265 },
266 );
267 }
268
269 pub fn register_group(
270 &mut self,
271 is_externally_loaded: bool,
272 name: &'static str,
273 deprecated_name: Option<&'static str>,
274 to: Vec<LintId>,
275 ) {
276 if let Some(deprecated) = deprecated_name {
277 self.insert_group(
278 deprecated,
279 LintGroup {
280 lint_ids: to.clone(),
281 is_externally_loaded,
282 depr: Some(LintAlias { name, silent: false }),
283 },
284 );
285 }
286 self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None });
287 }
288
289 #[track_caller]
293 pub fn register_ignored(&mut self, name: &str) {
294 if self.by_name.insert(name.to_string(), Ignored).is_some() {
295 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
name));bug!("duplicate specification of lint {}", name);
296 }
297 }
298
299 #[track_caller]
301 pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
302 let Some(&Id(target)) = self.by_name.get(new_name) else {
303 ::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);
304 };
305 self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
306 }
307
308 pub fn register_removed(&mut self, name: &str, reason: &str) {
309 self.by_name.insert(name.into(), Removed(reason.into()));
310 }
311
312 pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
313 match self.by_name.get(lint_name) {
314 Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
315 Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)),
316 Some(Removed(_)) => None,
317 Some(Ignored) => Some(&[]),
318 None => match self.lint_groups.get(lint_name) {
319 Some(LintGroup { lint_ids, .. }) => Some(lint_ids),
320 None => None,
321 },
322 }
323 }
324
325 pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
327 {
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:327",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(327u32),
::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!(
328 "is_lint_group(lint_name={:?}, lint_groups={:?})",
329 lint_name,
330 self.lint_groups.keys().collect::<Vec<_>>()
331 );
332 let lint_name_str = lint_name.as_str();
333 self.lint_groups.contains_key(lint_name_str) || {
334 let warnings_name_str = crate::WARNINGS.name_lower();
335 lint_name_str == warnings_name_str
336 }
337 }
338
339 pub fn check_lint_name(
347 &self,
348 lint_name: &str,
349 tool_name: Option<Symbol>,
350 registered_tools: &RegisteredTools,
351 ) -> CheckLintNameResult<'_> {
352 if let Some(tool_name) = tool_name {
353 if tool_name != sym::rustc
355 && tool_name != sym::rustdoc
356 && !registered_tools.contains(&Ident::with_dummy_span(tool_name))
357 {
358 return CheckLintNameResult::NoTool;
359 }
360 }
361
362 let complete_name = if let Some(tool_name) = tool_name {
363 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}")
364 } else {
365 lint_name.to_string()
366 };
367 if let Some(tool_name) = tool_name {
369 match self.by_name.get(&complete_name) {
370 None => match self.lint_groups.get(&*complete_name) {
371 None => {
373 {
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:375",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(375u32),
::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);
376 let tool_prefix = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::", tool_name))
})format!("{tool_name}::");
377
378 return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
379 self.no_lint_suggestion(&complete_name, tool_name.as_str())
380 } else {
381 CheckLintNameResult::MissingTool
384 };
385 }
386 Some(LintGroup { lint_ids, depr, .. }) => {
387 return if let &Some(LintAlias { name, silent: false }) = depr {
388 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
389 } else {
390 CheckLintNameResult::Tool(lint_ids, None)
391 };
392 }
393 },
394 Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
395 _ => {}
398 }
399 }
400 match self.by_name.get(&complete_name) {
401 Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
402 Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
403 None => match self.lint_groups.get(&*complete_name) {
404 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
407 Some(LintGroup { lint_ids, depr, .. }) => {
408 if let &Some(LintAlias { name, silent: false }) = depr {
410 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
411 } else {
412 CheckLintNameResult::Ok(lint_ids)
413 }
414 }
415 },
416 Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
417 Some(&Ignored) => CheckLintNameResult::Ok(&[]),
418 }
419 }
420
421 fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
422 let name_lower = lint_name.to_lowercase();
423
424 if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() {
425 return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
427 }
428
429 #[allow(rustc::potential_query_instability)]
435 let mut groups: Vec<_> = self
436 .lint_groups
437 .iter()
438 .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k))
439 .collect();
440 groups.sort();
441 let groups = groups.iter().map(|k| Symbol::intern(k));
442 let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
443 let names: Vec<Symbol> = groups.chain(lints).collect();
444 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)];
445 if let Some(stripped) = name_lower.split("::").last() {
446 lookups.push(Symbol::intern(stripped));
447 }
448 let res = find_best_match_for_names(&names, &lookups, None);
449 let is_rustc = res.map_or_else(
450 || false,
451 |s| name_lower.contains("::") && !s.as_str().starts_with(tool_name),
452 );
453 let suggestion = res.map(|s| (s, is_rustc));
454 CheckLintNameResult::NoLint(suggestion)
455 }
456
457 fn check_tool_name_for_backwards_compat(
458 &self,
459 lint_name: &str,
460 tool_name: &str,
461 ) -> CheckLintNameResult<'_> {
462 let complete_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}");
463 match self.by_name.get(&complete_name) {
464 None => match self.lint_groups.get(&*complete_name) {
465 None => self.no_lint_suggestion(lint_name, tool_name),
467 Some(LintGroup { lint_ids, .. }) => {
468 CheckLintNameResult::Tool(lint_ids, Some(complete_name))
469 }
470 },
471 Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)),
472 Some(other) => {
473 {
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:473",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(473u32),
::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);
474 CheckLintNameResult::NoLint(None)
475 }
476 }
477 }
478}
479
480pub struct LateContext<'tcx> {
482 pub tcx: TyCtxt<'tcx>,
484
485 pub enclosing_body: Option<hir::BodyId>,
487
488 pub(super) cached_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
493
494 pub param_env: ty::ParamEnv<'tcx>,
496
497 pub effective_visibilities: &'tcx EffectiveVisibilities,
499
500 pub last_node_with_lint_attrs: hir::HirId,
501
502 pub generics: Option<&'tcx hir::Generics<'tcx>>,
504
505 pub only_module: bool,
507}
508
509pub struct EarlyContext<'a> {
511 pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>,
512 pub buffered: LintBuffer,
513}
514
515pub trait LintContext {
516 type LintExpectationId: Copy + Into<LintExpectationId>;
517
518 fn sess(&self) -> &Session;
519
520 #[track_caller]
526 fn opt_span_lint<S: Into<MultiSpan>>(
527 &self,
528 lint: &'static Lint,
529 span: Option<S>,
530 decorate: impl for<'a> Diagnostic<'a, ()>,
531 );
532
533 #[track_caller]
536 fn emit_span_lint<S: Into<MultiSpan>>(
537 &self,
538 lint: &'static Lint,
539 span: S,
540 decorator: impl for<'a> Diagnostic<'a, ()>,
541 ) {
542 self.opt_span_lint(lint, Some(span), decorator);
543 }
544
545 fn get_lint_level_spec(&self, lint: &'static Lint) -> LevelSpec<Self::LintExpectationId>;
547
548 fn fulfill_expectation(&self, expectation: Self::LintExpectationId) {
556 self.sess()
561 .dcx()
562 .struct_expect(
563 "this is a dummy diagnostic, to submit and store an expectation",
564 expectation.into(),
565 )
566 .emit();
567 }
568}
569
570impl<'a> EarlyContext<'a> {
571 pub(crate) fn new(
572 sess: &'a Session,
573 features: &'a Features,
574 lint_added_lints: bool,
575 lint_store: &'a LintStore,
576 registered_tools: &'a RegisteredTools,
577 buffered: LintBuffer,
578 ) -> EarlyContext<'a> {
579 EarlyContext {
580 builder: LintLevelsBuilder::new(
581 sess,
582 features,
583 lint_added_lints,
584 lint_store,
585 registered_tools,
586 ),
587 buffered,
588 }
589 }
590}
591
592impl<'tcx> LintContext for LateContext<'tcx> {
593 type LintExpectationId = StableLintExpectationId;
594
595 fn sess(&self) -> &Session {
597 self.tcx.sess
598 }
599
600 fn opt_span_lint<S: Into<MultiSpan>>(
601 &self,
602 lint: &'static Lint,
603 span: Option<S>,
604 decorate: impl for<'a> Diagnostic<'a, ()>,
605 ) {
606 let hir_id = self.last_node_with_lint_attrs;
607
608 match span {
609 Some(s) => self.tcx.emit_node_span_lint(lint, hir_id, s, decorate),
610 None => self.tcx.emit_node_lint(lint, hir_id, decorate),
611 }
612 }
613
614 fn get_lint_level_spec(&self, lint: &'static Lint) -> StableLevelSpec {
615 self.tcx.lint_level_spec_at_node(lint, self.last_node_with_lint_attrs)
616 }
617}
618
619impl LintContext for EarlyContext<'_> {
620 type LintExpectationId = UnstableLintExpectationId;
621
622 fn sess(&self) -> &Session {
624 self.builder.sess()
625 }
626
627 fn opt_span_lint<S: Into<MultiSpan>>(
628 &self,
629 lint: &'static Lint,
630 span: Option<S>,
631 decorator: impl for<'a> Diagnostic<'a, ()>,
632 ) {
633 self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorator)
634 }
635
636 fn get_lint_level_spec(&self, lint: &'static Lint) -> UnstableLevelSpec {
637 self.builder.lint_level_spec(lint)
638 }
639}
640
641impl<'tcx> LateContext<'tcx> {
642 pub fn typing_mode(&self) -> TypingMode<'tcx> {
645 if let Some(body_id) = self.enclosing_body
646 && self.tcx.use_typing_mode_borrowck()
647 {
648 let def_id = self.tcx.hir_enclosing_body_owner(body_id.hir_id);
649 TypingMode::borrowck(self.tcx, def_id)
650 } else {
651 TypingMode::non_body_analysis()
652 }
653 }
654
655 pub fn typing_env(&self) -> TypingEnv<'tcx> {
656 TypingEnv::new(self.param_env, self.typing_mode())
657 }
658
659 pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
660 self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
661 }
662
663 pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
664 self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
665 }
666
667 pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
670 self.cached_typeck_results.get().or_else(|| {
671 self.enclosing_body.map(|body| {
672 let typeck_results = self.tcx.typeck_body(body);
673 self.cached_typeck_results.set(Some(typeck_results));
674 typeck_results
675 })
676 })
677 }
678
679 #[track_caller]
683 pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
684 self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body")
685 }
686
687 pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
691 match *qpath {
692 hir::QPath::Resolved(_, path) => path.res,
693 hir::QPath::TypeRelative(..) => self
694 .maybe_typeck_results()
695 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
696 .or_else(|| {
697 self.tcx
698 .has_typeck_results(id.owner.def_id)
699 .then(|| self.tcx.typeck(id.owner.def_id))
700 })
701 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
702 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
703 }
704 }
705
706 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
726 struct LintPathPrinter<'tcx> {
727 tcx: TyCtxt<'tcx>,
728 path: Vec<Symbol>,
729 }
730
731 impl<'tcx> Printer<'tcx> for LintPathPrinter<'tcx> {
732 fn tcx(&self) -> TyCtxt<'tcx> {
733 self.tcx
734 }
735
736 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
737 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
739
740 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
741 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
743
744 fn print_dyn_existential(
745 &mut self,
746 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
747 ) -> Result<(), PrintError> {
748 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
750
751 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
752 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
754
755 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
756 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)];
757 Ok(())
758 }
759
760 fn print_path_with_qualified(
761 &mut self,
762 self_ty: Ty<'tcx>,
763 trait_ref: Option<ty::TraitRef<'tcx>>,
764 ) -> Result<(), PrintError> {
765 if trait_ref.is_none()
766 && let ty::Adt(def, args) = self_ty.kind()
767 {
768 return self.print_def_path(def.did(), args);
769 }
770
771 {
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!({
773 self.path = vec![match trait_ref {
774 Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
775 None => Symbol::intern(&format!("<{self_ty}>")),
776 }];
777 Ok(())
778 })
779 }
780
781 fn print_path_with_impl(
782 &mut self,
783 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
784 self_ty: Ty<'tcx>,
785 trait_ref: Option<ty::TraitRef<'tcx>>,
786 ) -> Result<(), PrintError> {
787 print_prefix(self)?;
788
789 self.path.push(match trait_ref {
791 Some(trait_ref) => {
792 {
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!(
793 "<impl {} for {}>",
794 trait_ref.print_only_trait_path(),
795 self_ty
796 )))
797 }
798 None => {
799 {
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}>")))
800 }
801 });
802
803 Ok(())
804 }
805
806 fn print_path_with_simple(
807 &mut self,
808 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
809 disambiguated_data: &DisambiguatedDefPathData,
810 ) -> Result<(), PrintError> {
811 print_prefix(self)?;
812
813 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
815 return Ok(());
816 }
817
818 self.path.push(match disambiguated_data.data.get_opt_name() {
819 Some(sym) => sym,
820 None => Symbol::intern(&disambiguated_data.data.to_string()),
821 });
822 Ok(())
823 }
824
825 fn print_path_with_generic_args(
826 &mut self,
827 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
828 _args: &[GenericArg<'tcx>],
829 ) -> Result<(), PrintError> {
830 print_prefix(self)
831 }
832 }
833
834 let mut p = LintPathPrinter { tcx: self.tcx, path: ::alloc::vec::Vec::new()vec![] };
835 p.print_def_path(def_id, &[]).unwrap();
836 p.path
837 }
838
839 pub fn get_associated_type(
842 &self,
843 self_ty: Ty<'tcx>,
844 trait_id: DefId,
845 name: Symbol,
846 ) -> Option<Ty<'tcx>> {
847 let tcx = self.tcx;
848 tcx.associated_items(trait_id)
849 .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
850 .and_then(|assoc| {
851 let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
852 tcx.try_normalize_erasing_regions(self.typing_env(), Unnormalized::new_wip(proj))
853 .ok()
854 })
855 }
856
857 pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
861 let has_attr = |id: hir::HirId| -> bool {
862 self.tcx.hir_attrs(id).iter().any(hir::Attribute::is_prefix_attr_for_suggestions)
863 };
864 expr.precedence(&has_attr)
865 }
866
867 pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
883 expr = expr.peel_blocks();
884
885 while let hir::ExprKind::Path(ref qpath) = expr.kind
886 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
887 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
888 _ => None,
889 }
890 && let Some(init) = match parent_node {
891 hir::Node::Expr(expr) => Some(expr),
892 hir::Node::LetStmt(hir::LetStmt {
893 init,
894 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
896 ..
897 }) => *init,
898 _ => None,
899 }
900 {
901 expr = init.peel_blocks();
902 }
903 expr
904 }
905
906 pub fn expr_or_init_with_outside_body<'a>(
929 &self,
930 mut expr: &'a hir::Expr<'tcx>,
931 ) -> &'a hir::Expr<'tcx> {
932 expr = expr.peel_blocks();
933
934 while let hir::ExprKind::Path(ref qpath) = expr.kind
935 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
936 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
937 Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
938 _ => None,
939 }
940 && let Some(init) = match parent_node {
941 hir::Node::Expr(expr) => Some(expr),
942 hir::Node::LetStmt(hir::LetStmt {
943 init,
944 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
946 ..
947 }) => *init,
948 hir::Node::Item(item) => match item.kind {
949 hir::ItemKind::Const(.., hir::ConstItemRhs::Body(body_id))
951 | hir::ItemKind::Static(.., body_id) => Some(self.tcx.hir_body(body_id).value),
952 _ => None,
953 },
954 _ => None,
955 }
956 {
957 expr = init.peel_blocks();
958 }
959 expr
960 }
961}
962
963impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
964 #[inline]
965 fn data_layout(&self) -> &abi::TargetDataLayout {
966 &self.tcx.data_layout
967 }
968}
969
970impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
971 #[inline]
972 fn tcx(&self) -> TyCtxt<'tcx> {
973 self.tcx
974 }
975}
976
977impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
978 #[inline]
979 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
980 self.typing_env()
981 }
982}
983
984impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
985 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
986
987 #[inline]
988 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
989 err
990 }
991}