1use std::slice;
7
8use rustc_abi as abi;
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::{Diagnostic, LintBuffer, MultiSpan};
15use rustc_feature::Features;
16use rustc_hir as hir;
17use rustc_hir::def::Res;
18use rustc_hir::def_id::{CrateNum, DefId};
19use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
20use rustc_hir::{Pat, PatKind};
21use rustc_lint_defs::{
22 FutureIncompatibleInfo, Lint, LintExpectationId, LintId, StableLintExpectationId,
23 UnstableLintExpectationId,
24};
25use rustc_middle::lint::{LevelSpec, StableLevelSpec, UnstableLevelSpec};
26use rustc_middle::middle::privacy::EffectiveVisibilities;
27use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
28use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
29use rustc_middle::ty::{self, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode, Unnormalized};
30use rustc_session::{DynLintStore, Session};
31use rustc_span::edit_distance::find_best_match_for_names;
32use rustc_span::{Ident, Span, Symbol, bug, sym};
33use rustc_structures::LintName;
34use tracing::debug;
35
36use self::TargetLint::*;
37use crate::levels::LintLevelsBuilder;
38use crate::passes::{EarlyLintPassObject, LateLintPassObject};
39
40pub(crate) type EarlyLintPassFactory =
41 Box<dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync>;
42type LateLintPassFactory =
43 Box<dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync>;
44
45pub struct LintStore {
52 lints: Vec<&'static Lint>,
54
55 pub(crate) pre_expansion_lint_passes: Vec<EarlyLintPassFactory>,
62
63 pub(crate) early_lint_passes: Vec<EarlyLintPassFactory>,
65
66 pub(crate) late_lint_passes: Vec<LateLintPassFactory>,
75
76 pub(crate) late_lint_mod_passes: Vec<LateLintPassFactory>,
79
80 by_name: UnordMap<LintName, TargetLint>,
82
83 lint_groups: FxIndexMap<LintName, LintGroup>,
85}
86
87impl DynLintStore for LintStore {
88 fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = rustc_session::LintGroup> + '_> {
89 Box::new(self.get_lint_groups().map(|(name, lints, is_externally_loaded)| {
90 rustc_session::LintGroup { name, lints, is_externally_loaded }
91 }))
92 }
93}
94
95#[derive(#[automatically_derived]impl ::core::fmt::Debug for TargetLint {
#[inline]
#[rustc_trivial_field_reads]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::Id(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "Id",
&__self_0),
Self::Renamed(__self_0, __self_1) =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"Renamed", __self_0, &__self_1),
Self::Removed(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"Removed", &__self_0),
Self::Ignored => ::core::fmt::Formatter::write_str(f, "Ignored"),
}
}
}Debug)]
97enum TargetLint {
98 Id(LintId),
100
101 Renamed(LintName, LintId),
103
104 Removed(String),
107
108 Ignored,
113}
114
115struct LintAlias {
116 name: LintName,
117 silent: bool,
119}
120
121struct LintGroup {
122 lint_ids: Vec<LintId>,
123 is_externally_loaded: bool,
124 depr: Option<LintAlias>,
125}
126
127#[derive(#[automatically_derived]impl<'a> ::core::fmt::Debug for
CheckLintNameResult<'a> {
#[inline]
#[rustc_trivial_field_reads]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::Ok(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "Ok",
&__self_0),
Self::NoLint(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"NoLint", &__self_0),
Self::NoTool(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"NoTool", &__self_0),
Self::Renamed(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"Renamed", &__self_0),
Self::Removed(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"Removed", &__self_0),
Self::Tool(__self_0, __self_1) =>
::core::fmt::Formatter::debug_struct_field2_finish(f, "Tool",
__self_0, &__self_1),
Self::MissingTool =>
::core::fmt::Formatter::write_str(f, "MissingTool"),
}
}
}Debug)]
128pub enum CheckLintNameResult<'a> {
129 Ok(&'a [LintId]),
130 NoLint(Option<(LintName, bool)>),
132 NoTool(Symbol),
134 Renamed(LintName),
136 Removed(String),
138
139 Tool(&'a [LintId], Option<LintName>),
143
144 MissingTool,
148}
149
150impl LintStore {
151 pub fn new() -> LintStore {
152 LintStore {
153 lints: ::alloc::vec::Vec::new()vec![],
154 pre_expansion_lint_passes: ::alloc::vec::Vec::new()vec![],
155 early_lint_passes: ::alloc::vec::Vec::new()vec![],
156 late_lint_passes: ::alloc::vec::Vec::new()vec![],
157 late_lint_mod_passes: ::alloc::vec::Vec::new()vec![],
158 by_name: Default::default(),
159 lint_groups: Default::default(),
160 }
161 }
162
163 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
164 &self.lints
165 }
166
167 pub fn get_lint_groups(&self) -> impl Iterator<Item = (LintName, Vec<LintId>, bool)> {
168 self.lint_groups
169 .iter()
170 .filter(|(_, LintGroup { depr, .. })| {
171 depr.is_none()
173 })
174 .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
175 (k.clone(), lint_ids.clone(), *is_externally_loaded)
176 })
177 }
178
179 pub fn get_all_group_names(&self) -> impl Iterator<Item = LintName> {
181 self.lint_groups.keys().copied()
182 }
183
184 pub fn register_pre_expansion_lint_pass(&mut self, pass: EarlyLintPassFactory) {
186 self.pre_expansion_lint_passes.push(pass);
187 }
188
189 pub fn register_early_lint_pass(&mut self, pass: EarlyLintPassFactory) {
191 self.early_lint_passes.push(pass);
192 }
193
194 pub fn register_late_lint_pass(&mut self, pass: LateLintPassFactory) {
196 self.late_lint_passes.push(pass);
197 }
198
199 pub fn register_late_lint_mod_pass(&mut self, pass: LateLintPassFactory) {
201 self.late_lint_mod_passes.push(pass);
202 }
203
204 pub fn register_lints(&mut self, lints: &[&'static Lint]) {
206 for lint in lints {
207 self.lints.push(lint);
208
209 let id = LintId::of(lint);
210 if self.by_name.insert(LintName::from_str(&lint.name_lower()), Id(id)).is_some() {
211 ::rustc_span::macros::bug_impl(None,
format_args!("duplicate specification of lint {0}", lint.name_lower()),
Location::caller())bug!("duplicate specification of lint {}", lint.name_lower())
212 }
213
214 if let Some(FutureIncompatibleInfo { reason, .. }) = lint.future_incompatible {
215 if let Some(edition) = reason.edition() {
216 self.lint_groups
217 .entry(LintName::from_str(edition.lint_name()))
218 .or_insert(LintGroup {
219 lint_ids: ::alloc::vec::Vec::new()vec![],
220 is_externally_loaded: lint.is_externally_loaded,
221 depr: None,
222 })
223 .lint_ids
224 .push(id);
225 } else {
226 self.lint_groups
230 .entry(LintName::from_str("future_incompatible"))
231 .or_insert(LintGroup {
232 lint_ids: ::alloc::vec::Vec::new()vec![],
233 is_externally_loaded: lint.is_externally_loaded,
234 depr: None,
235 })
236 .lint_ids
237 .push(id);
238 }
239 }
240 }
241 }
242
243 fn insert_group(&mut self, name: LintName, group: LintGroup) {
244 let previous = self.lint_groups.insert(name, group);
245 if previous.is_some() {
246 ::rustc_span::macros::bug_impl(None,
format_args!("group {0} already exists", name), Location::caller());bug!("group {name} already exists");
247 }
248 }
249
250 pub fn register_group_alias(&mut self, group_name: &str, alias: &str) {
251 let group_name = LintName::from_str(group_name);
252 let alias = LintName::from_str(alias);
253 let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(&group_name) else {
254 ::rustc_span::macros::bug_impl(None,
format_args!("group alias {0:?} points to unregistered group {1:?}",
alias, group_name), Location::caller())bug!("group alias {alias:?} points to unregistered group {group_name:?}")
255 };
256
257 self.insert_group(
258 alias,
259 LintGroup {
260 lint_ids: lint_ids.clone(),
261 is_externally_loaded: false,
262 depr: Some(LintAlias { name: group_name, silent: true }),
263 },
264 );
265 }
266
267 pub fn register_group(
268 &mut self,
269 is_externally_loaded: bool,
270 name: &str,
271 deprecated_name: Option<&str>,
272 to: Vec<LintId>,
273 ) {
274 let name = LintName::from_str(name);
275 if let Some(deprecated) = deprecated_name {
276 let deprecated = LintName::from_str(deprecated);
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(LintName::from_str(name), Ignored).is_some() {
295 ::rustc_span::macros::bug_impl(None,
format_args!("duplicate specification of lint {0}", name),
Location::caller());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 old_name = LintName::from_str(old_name);
303 let new_name = LintName::from_str(new_name);
304 let Some(&Id(target)) = self.by_name.get(&new_name) else {
305 ::rustc_span::macros::bug_impl(None,
format_args!("invalid lint renaming of {0} to {1}", old_name, new_name),
Location::caller());bug!("invalid lint renaming of {old_name} to {new_name}");
306 };
307 self.by_name.insert(old_name, Renamed(new_name, target));
308 }
309
310 pub fn register_removed(&mut self, name: &str, reason: &str) {
311 self.by_name.insert(LintName::from_str(name), Removed(reason.into()));
312 }
313
314 pub fn find_lints(&self, lint_name: LintName) -> Option<&[LintId]> {
315 match self.by_name.get(&lint_name) {
316 Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
317 Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)),
318 Some(Removed(_)) => None,
319 Some(Ignored) => Some(&[]),
320 None => match self.lint_groups.get(&lint_name) {
321 Some(LintGroup { lint_ids, .. }) => Some(lint_ids),
322 None => None,
323 },
324 }
325 }
326
327 pub fn is_lint_group(&self, lint_name: LintName) -> bool {
329 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/compiler/rustc_lint/src/context.rs:329",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(329u32),
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::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 ::tracing::field::Value))])
});
} else { ; }
};debug!(
330 "is_lint_group(lint_name={:?}, lint_groups={:?})",
331 lint_name,
332 self.lint_groups.keys().collect::<Vec<_>>()
333 );
334 self.lint_groups.contains_key(&lint_name) || lint_name.is(sym::warnings)
335 }
336
337 pub fn check_lint_name(
345 &self,
346 lint_name: LintName,
347 registered_lint_tools: &RegisteredTools,
348 ) -> CheckLintNameResult<'_> {
349 let tool_name = lint_name.tool;
350
351 if let Some(tool_name) = tool_name {
352 if tool_name != sym::rustc
354 && tool_name != sym::rustdoc
355 && !registered_lint_tools.contains(&Ident::with_dummy_span(tool_name))
356 {
357 return CheckLintNameResult::NoTool(tool_name);
358 }
359 }
360
361 if let Some(tool_name) = tool_name {
363 match self.by_name.get(&lint_name) {
364 None => match self.lint_groups.get(&lint_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 /rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/compiler/rustc_lint/src/context.rs:369",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("lints={0:?}",
self.by_name) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("lints={:?}", self.by_name);
370
371 return if self.by_name.keys().any(|lint| lint.tool == Some(tool_name)) {
372 self.no_lint_suggestion(lint_name)
373 } else {
374 CheckLintNameResult::MissingTool
377 };
378 }
379 Some(LintGroup { lint_ids, depr, .. }) => {
380 return if let Some(LintAlias { name, silent: false }) = depr {
381 CheckLintNameResult::Tool(lint_ids, Some(*name))
382 } else {
383 CheckLintNameResult::Tool(lint_ids, None)
384 };
385 }
386 },
387 Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
388 _ => {}
391 }
392 }
393 match self.by_name.get(&lint_name) {
394 Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(*new_name),
395 Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
396 None => match self.lint_groups.get(&lint_name) {
397 None => self.no_lint_suggestion(lint_name),
398 Some(LintGroup { lint_ids, depr, .. }) => {
399 if let Some(LintAlias { name, silent: false }) = depr {
401 CheckLintNameResult::Tool(lint_ids, Some(*name))
402 } else {
403 CheckLintNameResult::Ok(lint_ids)
404 }
405 }
406 },
407 Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
408 Some(&Ignored) => CheckLintNameResult::Ok(&[]),
409 }
410 }
411
412 fn no_lint_suggestion(&self, lint_name: LintName) -> CheckLintNameResult<'_> {
413 let name_lower = lint_name.to_lowercase();
414
415 if self.find_lints(name_lower).is_some() {
416 return CheckLintNameResult::NoLint(Some((name_lower, false)));
418 }
419
420 #[allow(rustc::potential_query_instability)]
426 let mut groups: Vec<_> = self
427 .lint_groups
428 .iter()
429 .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k))
430 .collect();
431 groups.sort();
432 let groups = groups.iter().map(|k| Symbol::intern(&k.to_string()));
433 let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
434 let names: Vec<Symbol> = groups.chain(lints).collect();
435 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.to_string())]))vec![Symbol::intern(&name_lower.to_string())];
436 if let Some(stripped) = name_lower.name.as_str().split("::").last() {
437 lookups.push(Symbol::intern(stripped));
438 }
439 let res = find_best_match_for_names(&names, &lookups, None);
440 let res = res.map(|s| LintName::from_str(s.as_str()));
441 let is_builtin =
442 res.as_ref().map(|s| lint_name.tool.is_some() && s.tool.is_none()).unwrap_or(false);
443 let suggestion = res.map(|s| (s, is_builtin));
444 CheckLintNameResult::NoLint(suggestion)
445 }
446}
447
448pub struct LateContext<'tcx> {
450 pub tcx: TyCtxt<'tcx>,
452
453 pub enclosing_body: Option<hir::BodyId>,
455
456 pub typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
458
459 pub param_env: ty::ParamEnv<'tcx>,
461
462 pub effective_visibilities: &'tcx EffectiveVisibilities,
464
465 pub last_node_with_lint_attrs: hir::HirId,
466
467 pub generics: Option<&'tcx hir::Generics<'tcx>>,
469
470 pub only_module: bool,
472}
473
474pub struct EarlyContext<'a> {
476 pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>,
477 pub buffered: LintBuffer,
478}
479
480pub trait LintContext {
481 type LintExpectationId: Copy + Into<LintExpectationId>;
482
483 fn sess(&self) -> &Session;
484
485 #[track_caller]
491 fn opt_span_lint<S: Into<MultiSpan>>(
492 &self,
493 lint: &'static Lint,
494 span: Option<S>,
495 decorate: impl for<'a> Diagnostic<'a>,
496 );
497
498 #[track_caller]
501 fn emit_span_lint<S: Into<MultiSpan>>(
502 &self,
503 lint: &'static Lint,
504 span: S,
505 decorator: impl for<'a> Diagnostic<'a>,
506 ) {
507 self.opt_span_lint(lint, Some(span), decorator);
508 }
509
510 fn get_lint_level_spec(&self, lint: &'static Lint) -> LevelSpec<Self::LintExpectationId>;
512
513 fn fulfill_expectation(&self, expectation: Self::LintExpectationId) {
521 self.sess().dcx().fulfill_expectation(expectation);
522 }
523}
524
525impl<'a> EarlyContext<'a> {
526 pub(crate) fn new(
527 sess: &'a Session,
528 features: &'a Features,
529 lint_added_lints: bool,
530 lint_store: &'a LintStore,
531 registered_lint_tools: &'a RegisteredTools,
532 buffered: LintBuffer,
533 ) -> EarlyContext<'a> {
534 EarlyContext {
535 builder: LintLevelsBuilder::new(
536 sess,
537 features,
538 lint_added_lints,
539 lint_store,
540 registered_lint_tools,
541 ),
542 buffered,
543 }
544 }
545}
546
547impl<'tcx> LintContext for LateContext<'tcx> {
548 type LintExpectationId = StableLintExpectationId;
549
550 fn sess(&self) -> &Session {
552 self.tcx.sess
553 }
554
555 fn opt_span_lint<S: Into<MultiSpan>>(
556 &self,
557 lint: &'static Lint,
558 span: Option<S>,
559 decorate: impl for<'a> Diagnostic<'a>,
560 ) {
561 let hir_id = self.last_node_with_lint_attrs;
562
563 match span {
564 Some(s) => self.tcx.emit_node_span_lint(lint, hir_id, s, decorate),
565 None => self.tcx.emit_node_lint(lint, hir_id, decorate),
566 }
567 }
568
569 fn get_lint_level_spec(&self, lint: &'static Lint) -> StableLevelSpec {
570 self.tcx.lint_level_spec_at_node(lint, self.last_node_with_lint_attrs)
571 }
572}
573
574impl LintContext for EarlyContext<'_> {
575 type LintExpectationId = UnstableLintExpectationId;
576
577 fn sess(&self) -> &Session {
579 self.builder.sess()
580 }
581
582 fn opt_span_lint<S: Into<MultiSpan>>(
583 &self,
584 lint: &'static Lint,
585 span: Option<S>,
586 decorator: impl for<'a> Diagnostic<'a>,
587 ) {
588 self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorator)
589 }
590
591 fn get_lint_level_spec(&self, lint: &'static Lint) -> UnstableLevelSpec {
592 self.builder.lint_level_spec(lint)
593 }
594}
595
596impl<'tcx> LateContext<'tcx> {
597 pub fn typing_mode(&self) -> TypingMode<'tcx> {
600 if let Some(body_id) = self.enclosing_body
601 && self.tcx.use_typing_mode_post_typeck_through_borrowck()
602 {
603 let def_id = self.tcx.hir_enclosing_body_owner(body_id.hir_id);
604 TypingMode::post_borrowck_analysis(self.tcx, def_id)
605 } else {
606 TypingMode::non_body_analysis()
607 }
608 }
609
610 pub fn typing_env(&self) -> TypingEnv<'tcx> {
611 TypingEnv::new(self.param_env, self.typing_mode())
612 }
613
614 pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
615 self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
616 }
617
618 pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
619 self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
620 }
621
622 #[inline]
626 #[track_caller]
627 pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
628 self.typeck_results.expect("`LateContext::typeck_results` called outside of body")
629 }
630
631 pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
635 match *qpath {
636 hir::QPath::Resolved(_, path) => path.res,
637 hir::QPath::TypeRelative(..) => self
638 .typeck_results
639 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
640 .or_else(|| {
641 self.tcx
642 .has_typeck_results(id.owner.def_id)
643 .then(|| self.tcx.typeck(id.owner.def_id))
644 })
645 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
646 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
647 }
648 }
649
650 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
670 struct LintPathPrinter<'tcx> {
671 tcx: TyCtxt<'tcx>,
672 path: Vec<Symbol>,
673 }
674
675 impl<'tcx> Printer<'tcx> for LintPathPrinter<'tcx> {
676 fn tcx(&self) -> TyCtxt<'tcx> {
677 self.tcx
678 }
679
680 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
681 ::core::panicking::unreachable_default_msg();unreachable!(); }
683
684 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
685 ::core::panicking::unreachable_default_msg();unreachable!(); }
687
688 fn print_dyn_existential(
689 &mut self,
690 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
691 ) -> Result<(), PrintError> {
692 ::core::panicking::unreachable_default_msg();unreachable!(); }
694
695 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
696 ::core::panicking::unreachable_default_msg();unreachable!(); }
698
699 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
700 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)];
701 Ok(())
702 }
703
704 fn print_path_with_qualified(
705 &mut self,
706 self_ty: Ty<'tcx>,
707 trait_ref: Option<ty::TraitRef<'tcx>>,
708 ) -> Result<(), PrintError> {
709 if trait_ref.is_none()
710 && let ty::Adt(def, args) = self_ty.kind()
711 {
712 return self.print_def_path(def.did(), *args);
713 }
714
715 {
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!({
717 self.path = vec![match trait_ref {
718 Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
719 None => Symbol::intern(&format!("<{self_ty}>")),
720 }];
721 Ok(())
722 })
723 }
724
725 fn print_path_with_impl(
726 &mut self,
727 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
728 self_ty: Ty<'tcx>,
729 trait_ref: Option<ty::TraitRef<'tcx>>,
730 ) -> Result<(), PrintError> {
731 print_prefix(self)?;
732
733 self.path.push(match trait_ref {
735 Some(trait_ref) => {
736 {
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!(
737 "<impl {} for {}>",
738 trait_ref.print_only_trait_path(),
739 self_ty
740 )))
741 }
742 None => {
743 {
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}>")))
744 }
745 });
746
747 Ok(())
748 }
749
750 fn print_path_with_simple(
751 &mut self,
752 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
753 disambiguated_data: &DisambiguatedDefPathData,
754 ) -> Result<(), PrintError> {
755 print_prefix(self)?;
756
757 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
759 return Ok(());
760 }
761
762 self.path.push(match disambiguated_data.data.get_opt_name() {
763 Some(sym) => sym,
764 None => Symbol::intern(&disambiguated_data.data.to_string()),
765 });
766 Ok(())
767 }
768
769 fn print_path_with_generic_args(
770 &mut self,
771 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
772 _args: ty::GenericArgs<'tcx>,
773 ) -> Result<(), PrintError> {
774 print_prefix(self)
775 }
776 }
777
778 let mut p = LintPathPrinter { tcx: self.tcx, path: ::alloc::vec::Vec::new()vec![] };
779 p.print_def_path(def_id, ty::GenericArgs::empty()).unwrap();
780 p.path
781 }
782
783 pub fn get_associated_type(
786 &self,
787 self_ty: Ty<'tcx>,
788 trait_id: DefId,
789 name: Symbol,
790 ) -> Option<Ty<'tcx>> {
791 let tcx = self.tcx;
792 tcx.associated_items(trait_id)
793 .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
794 .and_then(|assoc| {
795 let proj = Ty::new_projection(tcx, ty::IsRigid::No, assoc.def_id, [self_ty]);
796 tcx.try_normalize_erasing_regions(self.typing_env(), Unnormalized::new_wip(proj))
797 .ok()
798 })
799 }
800
801 pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
805 let has_attr = |id: hir::HirId| -> bool {
806 self.tcx
807 .hir_attrs(id)
808 .iter()
809 .any(rustc_attr_ir::Attribute::is_prefix_attr_for_suggestions)
810 };
811 expr.precedence(&has_attr)
812 }
813
814 pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
830 expr = expr.peel_blocks();
831
832 while let hir::ExprKind::Path(ref qpath) = expr.kind
833 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
834 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
835 _ => None,
836 }
837 && let Some(init) = match parent_node {
838 hir::Node::Expr(expr) => Some(expr),
839 hir::Node::LetStmt(hir::LetStmt {
840 init,
841 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
843 ..
844 }) => *init,
845 _ => None,
846 }
847 {
848 expr = init.peel_blocks();
849 }
850 expr
851 }
852
853 pub fn expr_or_init_with_outside_body<'a>(
876 &self,
877 mut expr: &'a hir::Expr<'tcx>,
878 ) -> &'a hir::Expr<'tcx> {
879 expr = expr.peel_blocks();
880
881 while let hir::ExprKind::Path(ref qpath) = expr.kind
882 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
883 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
884 Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
885 _ => None,
886 }
887 && let Some(init) = match parent_node {
888 hir::Node::Expr(expr) => Some(expr),
889 hir::Node::LetStmt(hir::LetStmt {
890 init,
891 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
893 ..
894 }) => *init,
895 hir::Node::Item(item) => match item.kind {
896 hir::ItemKind::Const(.., hir::ConstItemRhs::Body(body_id))
898 | hir::ItemKind::Static(.., body_id) => Some(self.tcx.hir_body(body_id).value),
899 _ => None,
900 },
901 _ => None,
902 }
903 {
904 expr = init.peel_blocks();
905 }
906 expr
907 }
908}
909
910impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
911 #[inline]
912 fn data_layout(&self) -> &abi::TargetDataLayout {
913 &self.tcx.data_layout
914 }
915}
916
917impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
918 #[inline]
919 fn tcx(&self) -> TyCtxt<'tcx> {
920 self.tcx
921 }
922}
923
924impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
925 #[inline]
926 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
927 self.typing_env()
928 }
929}
930
931impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
932 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
933
934 #[inline]
935 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
936 err
937 }
938}