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::LevelAndSource;
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::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode};
28use rustc_session::lint::{
29 CheckLintNameResult, FutureIncompatibleInfo, Lint, LintExpectationId, LintId, TargetLint,
30};
31use rustc_session::{DynLintStore, Session};
32use rustc_span::edit_distance::find_best_match_for_names;
33use rustc_span::{Ident, Span, Symbol, sym};
34use tracing::debug;
35
36use self::TargetLint::*;
37use crate::levels::LintLevelsBuilder;
38use crate::passes::{EarlyLintPassObject, LateLintPassObject};
39
40type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync;
41type LateLintPassFactory =
42 dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
43
44pub struct LintStore {
46 lints: Vec<&'static Lint>,
48
49 pub pre_expansion_passes: Vec<Box<EarlyLintPassFactory>>,
56 pub early_passes: Vec<Box<EarlyLintPassFactory>>,
57 pub late_passes: Vec<Box<LateLintPassFactory>>,
58 pub late_module_passes: Vec<Box<LateLintPassFactory>>,
60
61 by_name: UnordMap<String, TargetLint>,
63
64 lint_groups: FxIndexMap<&'static str, LintGroup>,
66}
67
68impl DynLintStore for LintStore {
69 fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = rustc_session::LintGroup> + '_> {
70 Box::new(self.get_lint_groups().map(|(name, lints, is_externally_loaded)| {
71 rustc_session::LintGroup { name, lints, is_externally_loaded }
72 }))
73 }
74
75 fn check_lint_name(
76 &self,
77 lint_name: &str,
78 tool_name: Option<Symbol>,
79 registered_tools: &RegisteredTools,
80 ) -> CheckLintNameResult<'_> {
81 self.check_lint_name(lint_name, tool_name, registered_tools)
82 }
83
84 fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
85 self.find_lints(lint_name)
86 }
87}
88
89struct LintAlias {
90 name: &'static str,
91 silent: bool,
93}
94
95struct LintGroup {
96 lint_ids: Vec<LintId>,
97 is_externally_loaded: bool,
98 depr: Option<LintAlias>,
99}
100
101impl LintStore {
102 pub fn new() -> LintStore {
103 LintStore {
104 lints: ::alloc::vec::Vec::new()vec![],
105 pre_expansion_passes: ::alloc::vec::Vec::new()vec![],
106 early_passes: ::alloc::vec::Vec::new()vec![],
107 late_passes: ::alloc::vec::Vec::new()vec![],
108 late_module_passes: ::alloc::vec::Vec::new()vec![],
109 by_name: Default::default(),
110 lint_groups: Default::default(),
111 }
112 }
113
114 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
115 &self.lints
116 }
117
118 pub fn get_lint_groups(&self) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> {
119 self.lint_groups
120 .iter()
121 .filter(|(_, LintGroup { depr, .. })| {
122 depr.is_none()
124 })
125 .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
126 (*k, lint_ids.clone(), *is_externally_loaded)
127 })
128 }
129
130 pub fn get_all_group_names(&self) -> impl Iterator<Item = &'static str> {
132 self.lint_groups.keys().copied()
133 }
134
135 pub fn register_early_pass(
136 &mut self,
137 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
138 ) {
139 self.early_passes.push(Box::new(pass));
140 }
141
142 pub fn register_pre_expansion_pass(
149 &mut self,
150 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
151 ) {
152 self.pre_expansion_passes.push(Box::new(pass));
153 }
154
155 pub fn register_late_pass(
156 &mut self,
157 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
158 + 'static
159 + sync::DynSend
160 + sync::DynSync,
161 ) {
162 self.late_passes.push(Box::new(pass));
163 }
164
165 pub fn register_late_mod_pass(
166 &mut self,
167 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
168 + 'static
169 + sync::DynSend
170 + sync::DynSync,
171 ) {
172 self.late_module_passes.push(Box::new(pass));
173 }
174
175 pub fn register_lints(&mut self, lints: &[&'static Lint]) {
177 for lint in lints {
178 self.lints.push(lint);
179
180 let id = LintId::of(lint);
181 if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
182 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
lint.name_lower()))bug!("duplicate specification of lint {}", lint.name_lower())
183 }
184
185 if let Some(FutureIncompatibleInfo { reason, .. }) = lint.future_incompatible {
186 if let Some(edition) = reason.edition() {
187 self.lint_groups
188 .entry(edition.lint_name())
189 .or_insert(LintGroup {
190 lint_ids: ::alloc::vec::Vec::new()vec![],
191 is_externally_loaded: lint.is_externally_loaded,
192 depr: None,
193 })
194 .lint_ids
195 .push(id);
196 } else {
197 self.lint_groups
201 .entry("future_incompatible")
202 .or_insert(LintGroup {
203 lint_ids: ::alloc::vec::Vec::new()vec![],
204 is_externally_loaded: lint.is_externally_loaded,
205 depr: None,
206 })
207 .lint_ids
208 .push(id);
209 }
210 }
211 }
212 }
213
214 fn insert_group(&mut self, name: &'static str, group: LintGroup) {
215 let previous = self.lint_groups.insert(name, group);
216 if previous.is_some() {
217 ::rustc_middle::util::bug::bug_fmt(format_args!("group {0:?} already exists",
name));bug!("group {name:?} already exists");
218 }
219 }
220
221 pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) {
222 let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else {
223 ::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:?}")
224 };
225
226 self.insert_group(
227 alias,
228 LintGroup {
229 lint_ids: lint_ids.clone(),
230 is_externally_loaded: false,
231 depr: Some(LintAlias { name: group_name, silent: true }),
232 },
233 );
234 }
235
236 pub fn register_group(
237 &mut self,
238 is_externally_loaded: bool,
239 name: &'static str,
240 deprecated_name: Option<&'static str>,
241 to: Vec<LintId>,
242 ) {
243 if let Some(deprecated) = deprecated_name {
244 self.insert_group(
245 deprecated,
246 LintGroup {
247 lint_ids: to.clone(),
248 is_externally_loaded,
249 depr: Some(LintAlias { name, silent: false }),
250 },
251 );
252 }
253 self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None });
254 }
255
256 #[track_caller]
260 pub fn register_ignored(&mut self, name: &str) {
261 if self.by_name.insert(name.to_string(), Ignored).is_some() {
262 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
name));bug!("duplicate specification of lint {}", name);
263 }
264 }
265
266 #[track_caller]
268 pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
269 let Some(&Id(target)) = self.by_name.get(new_name) else {
270 ::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);
271 };
272 self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
273 }
274
275 pub fn register_removed(&mut self, name: &str, reason: &str) {
276 self.by_name.insert(name.into(), Removed(reason.into()));
277 }
278
279 pub fn get_lint_by_name(&self, lint_name: &str) -> Option<&TargetLint> {
280 self.by_name.get(lint_name)
281 }
282
283 pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
284 match self.by_name.get(lint_name) {
285 Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
286 Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)),
287 Some(Removed(_)) => None,
288 Some(Ignored) => Some(&[]),
289 None => match self.lint_groups.get(lint_name) {
290 Some(LintGroup { lint_ids, .. }) => Some(lint_ids),
291 None => None,
292 },
293 }
294 }
295
296 pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
298 {
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:298",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(298u32),
::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!(
299 "is_lint_group(lint_name={:?}, lint_groups={:?})",
300 lint_name,
301 self.lint_groups.keys().collect::<Vec<_>>()
302 );
303 let lint_name_str = lint_name.as_str();
304 self.lint_groups.contains_key(lint_name_str) || {
305 let warnings_name_str = crate::WARNINGS.name_lower();
306 lint_name_str == warnings_name_str
307 }
308 }
309
310 pub fn check_lint_name(
318 &self,
319 lint_name: &str,
320 tool_name: Option<Symbol>,
321 registered_tools: &RegisteredTools,
322 ) -> CheckLintNameResult<'_> {
323 if let Some(tool_name) = tool_name {
324 if tool_name != sym::rustc
326 && tool_name != sym::rustdoc
327 && !registered_tools.contains(&Ident::with_dummy_span(tool_name))
328 {
329 return CheckLintNameResult::NoTool;
330 }
331 }
332
333 let complete_name = if let Some(tool_name) = tool_name {
334 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}")
335 } else {
336 lint_name.to_string()
337 };
338 if let Some(tool_name) = tool_name {
340 match self.by_name.get(&complete_name) {
341 None => match self.lint_groups.get(&*complete_name) {
342 None => {
344 {
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:346",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(346u32),
::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);
347 let tool_prefix = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::", tool_name))
})format!("{tool_name}::");
348
349 return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
350 self.no_lint_suggestion(&complete_name, tool_name.as_str())
351 } else {
352 CheckLintNameResult::MissingTool
355 };
356 }
357 Some(LintGroup { lint_ids, depr, .. }) => {
358 return if let &Some(LintAlias { name, silent: false }) = depr {
359 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
360 } else {
361 CheckLintNameResult::Tool(lint_ids, None)
362 };
363 }
364 },
365 Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
366 _ => {}
369 }
370 }
371 match self.by_name.get(&complete_name) {
372 Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(Symbol::intern(new_name)),
373 Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
374 None => match self.lint_groups.get(&*complete_name) {
375 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
378 Some(LintGroup { lint_ids, depr, .. }) => {
379 if let &Some(LintAlias { name, silent: false }) = depr {
381 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
382 } else {
383 CheckLintNameResult::Ok(lint_ids)
384 }
385 }
386 },
387 Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
388 Some(&Ignored) => CheckLintNameResult::Ok(&[]),
389 }
390 }
391
392 fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
393 let name_lower = lint_name.to_lowercase();
394
395 if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() {
396 return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
398 }
399
400 #[allow(rustc::potential_query_instability)]
406 let mut groups: Vec<_> = self
407 .lint_groups
408 .iter()
409 .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k))
410 .collect();
411 groups.sort();
412 let groups = groups.iter().map(|k| Symbol::intern(k));
413 let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
414 let names: Vec<Symbol> = groups.chain(lints).collect();
415 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)];
416 if let Some(stripped) = name_lower.split("::").last() {
417 lookups.push(Symbol::intern(stripped));
418 }
419 let res = find_best_match_for_names(&names, &lookups, None);
420 let is_rustc = res.map_or_else(
421 || false,
422 |s| name_lower.contains("::") && !s.as_str().starts_with(tool_name),
423 );
424 let suggestion = res.map(|s| (s, is_rustc));
425 CheckLintNameResult::NoLint(suggestion)
426 }
427
428 fn check_tool_name_for_backwards_compat(
429 &self,
430 lint_name: &str,
431 tool_name: &str,
432 ) -> CheckLintNameResult<'_> {
433 let complete_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}");
434 match self.by_name.get(&complete_name) {
435 None => match self.lint_groups.get(&*complete_name) {
436 None => self.no_lint_suggestion(lint_name, tool_name),
438 Some(LintGroup { lint_ids, .. }) => {
439 CheckLintNameResult::Tool(lint_ids, Some(complete_name))
440 }
441 },
442 Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)),
443 Some(other) => {
444 {
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:444",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(444u32),
::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);
445 CheckLintNameResult::NoLint(None)
446 }
447 }
448 }
449}
450
451pub struct LateContext<'tcx> {
453 pub tcx: TyCtxt<'tcx>,
455
456 pub enclosing_body: Option<hir::BodyId>,
458
459 pub(super) cached_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
464
465 pub param_env: ty::ParamEnv<'tcx>,
467
468 pub effective_visibilities: &'tcx EffectiveVisibilities,
470
471 pub last_node_with_lint_attrs: hir::HirId,
472
473 pub generics: Option<&'tcx hir::Generics<'tcx>>,
475
476 pub only_module: bool,
478}
479
480pub struct EarlyContext<'a> {
482 pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>,
483 pub buffered: LintBuffer,
484}
485
486pub trait LintContext {
487 fn sess(&self) -> &Session;
488
489 #[track_caller]
495 fn opt_span_lint<S: Into<MultiSpan>>(
496 &self,
497 lint: &'static Lint,
498 span: Option<S>,
499 decorate: impl for<'a> Diagnostic<'a, ()>,
500 );
501
502 #[track_caller]
505 fn emit_span_lint<S: Into<MultiSpan>>(
506 &self,
507 lint: &'static Lint,
508 span: S,
509 decorator: impl for<'a> Diagnostic<'a, ()>,
510 ) {
511 self.opt_span_lint(lint, Some(span), decorator);
512 }
513
514 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource;
516
517 fn fulfill_expectation(&self, expectation: LintExpectationId) {
525 self.sess()
530 .dcx()
531 .struct_expect(
532 "this is a dummy diagnostic, to submit and store an expectation",
533 expectation,
534 )
535 .emit();
536 }
537}
538
539impl<'a> EarlyContext<'a> {
540 pub(crate) fn new(
541 sess: &'a Session,
542 features: &'a Features,
543 lint_added_lints: bool,
544 lint_store: &'a LintStore,
545 registered_tools: &'a RegisteredTools,
546 buffered: LintBuffer,
547 ) -> EarlyContext<'a> {
548 EarlyContext {
549 builder: LintLevelsBuilder::new(
550 sess,
551 features,
552 lint_added_lints,
553 lint_store,
554 registered_tools,
555 ),
556 buffered,
557 }
558 }
559}
560
561impl<'tcx> LintContext for LateContext<'tcx> {
562 fn sess(&self) -> &Session {
564 self.tcx.sess
565 }
566
567 fn opt_span_lint<S: Into<MultiSpan>>(
568 &self,
569 lint: &'static Lint,
570 span: Option<S>,
571 decorate: impl for<'a> Diagnostic<'a, ()>,
572 ) {
573 let hir_id = self.last_node_with_lint_attrs;
574
575 match span {
576 Some(s) => self.tcx.emit_node_span_lint(lint, hir_id, s, decorate),
577 None => self.tcx.emit_node_lint(lint, hir_id, decorate),
578 }
579 }
580
581 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
584 self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs)
585 }
586}
587
588impl LintContext for EarlyContext<'_> {
589 fn sess(&self) -> &Session {
591 self.builder.sess()
592 }
593
594 fn opt_span_lint<S: Into<MultiSpan>>(
595 &self,
596 lint: &'static Lint,
597 span: Option<S>,
598 decorator: impl for<'a> Diagnostic<'a, ()>,
599 ) {
600 self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorator)
601 }
602
603 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
604 self.builder.lint_level(lint)
605 }
606}
607
608impl<'tcx> LateContext<'tcx> {
609 pub fn typing_mode(&self) -> TypingMode<'tcx> {
612 TypingMode::non_body_analysis()
615 }
616
617 pub fn typing_env(&self) -> TypingEnv<'tcx> {
618 TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
619 }
620
621 pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
622 self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
623 }
624
625 pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
626 self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
627 }
628
629 pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
632 self.cached_typeck_results.get().or_else(|| {
633 self.enclosing_body.map(|body| {
634 let typeck_results = self.tcx.typeck_body(body);
635 self.cached_typeck_results.set(Some(typeck_results));
636 typeck_results
637 })
638 })
639 }
640
641 #[track_caller]
645 pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
646 self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body")
647 }
648
649 pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
653 match *qpath {
654 hir::QPath::Resolved(_, path) => path.res,
655 hir::QPath::TypeRelative(..) => self
656 .maybe_typeck_results()
657 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
658 .or_else(|| {
659 self.tcx
660 .has_typeck_results(id.owner.def_id)
661 .then(|| self.tcx.typeck(id.owner.def_id))
662 })
663 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
664 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
665 }
666 }
667
668 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
688 struct LintPathPrinter<'tcx> {
689 tcx: TyCtxt<'tcx>,
690 path: Vec<Symbol>,
691 }
692
693 impl<'tcx> Printer<'tcx> for LintPathPrinter<'tcx> {
694 fn tcx(&self) -> TyCtxt<'tcx> {
695 self.tcx
696 }
697
698 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
699 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
701
702 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
703 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
705
706 fn print_dyn_existential(
707 &mut self,
708 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
709 ) -> Result<(), PrintError> {
710 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
712
713 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
714 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
716
717 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
718 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)];
719 Ok(())
720 }
721
722 fn print_path_with_qualified(
723 &mut self,
724 self_ty: Ty<'tcx>,
725 trait_ref: Option<ty::TraitRef<'tcx>>,
726 ) -> Result<(), PrintError> {
727 if trait_ref.is_none()
728 && let ty::Adt(def, args) = self_ty.kind()
729 {
730 return self.print_def_path(def.did(), args);
731 }
732
733 {
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!({
735 self.path = vec![match trait_ref {
736 Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
737 None => Symbol::intern(&format!("<{self_ty}>")),
738 }];
739 Ok(())
740 })
741 }
742
743 fn print_path_with_impl(
744 &mut self,
745 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
746 self_ty: Ty<'tcx>,
747 trait_ref: Option<ty::TraitRef<'tcx>>,
748 ) -> Result<(), PrintError> {
749 print_prefix(self)?;
750
751 self.path.push(match trait_ref {
753 Some(trait_ref) => {
754 {
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!(
755 "<impl {} for {}>",
756 trait_ref.print_only_trait_path(),
757 self_ty
758 )))
759 }
760 None => {
761 {
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}>")))
762 }
763 });
764
765 Ok(())
766 }
767
768 fn print_path_with_simple(
769 &mut self,
770 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
771 disambiguated_data: &DisambiguatedDefPathData,
772 ) -> Result<(), PrintError> {
773 print_prefix(self)?;
774
775 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
777 return Ok(());
778 }
779
780 self.path.push(match disambiguated_data.data.get_opt_name() {
781 Some(sym) => sym,
782 None => Symbol::intern(&disambiguated_data.data.to_string()),
783 });
784 Ok(())
785 }
786
787 fn print_path_with_generic_args(
788 &mut self,
789 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
790 _args: &[GenericArg<'tcx>],
791 ) -> Result<(), PrintError> {
792 print_prefix(self)
793 }
794 }
795
796 let mut p = LintPathPrinter { tcx: self.tcx, path: ::alloc::vec::Vec::new()vec![] };
797 p.print_def_path(def_id, &[]).unwrap();
798 p.path
799 }
800
801 pub fn get_associated_type(
804 &self,
805 self_ty: Ty<'tcx>,
806 trait_id: DefId,
807 name: Symbol,
808 ) -> Option<Ty<'tcx>> {
809 let tcx = self.tcx;
810 tcx.associated_items(trait_id)
811 .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
812 .and_then(|assoc| {
813 let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
814 tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()
815 })
816 }
817
818 pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
822 let has_attr = |id: hir::HirId| -> bool {
823 self.tcx.hir_attrs(id).iter().any(hir::Attribute::has_span_without_desugaring_kind)
824 };
825 expr.precedence(&has_attr)
826 }
827
828 pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
844 expr = expr.peel_blocks();
845
846 while let hir::ExprKind::Path(ref qpath) = expr.kind
847 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
848 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
849 _ => None,
850 }
851 && let Some(init) = match parent_node {
852 hir::Node::Expr(expr) => Some(expr),
853 hir::Node::LetStmt(hir::LetStmt {
854 init,
855 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
857 ..
858 }) => *init,
859 _ => None,
860 }
861 {
862 expr = init.peel_blocks();
863 }
864 expr
865 }
866
867 pub fn expr_or_init_with_outside_body<'a>(
890 &self,
891 mut expr: &'a hir::Expr<'tcx>,
892 ) -> &'a hir::Expr<'tcx> {
893 expr = expr.peel_blocks();
894
895 while let hir::ExprKind::Path(ref qpath) = expr.kind
896 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
897 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
898 Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
899 _ => None,
900 }
901 && let Some(init) = match parent_node {
902 hir::Node::Expr(expr) => Some(expr),
903 hir::Node::LetStmt(hir::LetStmt {
904 init,
905 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
907 ..
908 }) => *init,
909 hir::Node::Item(item) => match item.kind {
910 hir::ItemKind::Const(.., hir::ConstItemRhs::Body(body_id))
912 | hir::ItemKind::Static(.., body_id) => Some(self.tcx.hir_body(body_id).value),
913 _ => None,
914 },
915 _ => None,
916 }
917 {
918 expr = init.peel_blocks();
919 }
920 expr
921 }
922}
923
924impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
925 #[inline]
926 fn data_layout(&self) -> &abi::TargetDataLayout {
927 &self.tcx.data_layout
928 }
929}
930
931impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
932 #[inline]
933 fn tcx(&self) -> TyCtxt<'tcx> {
934 self.tcx
935 }
936}
937
938impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
939 #[inline]
940 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
941 self.typing_env()
942 }
943}
944
945impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
946 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
947
948 #[inline]
949 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
950 err
951 }
952}