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
43pub(crate) type EarlyLintPassFactory =
44 Box<dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync>;
45type LateLintPassFactory =
46 Box<dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync>;
47
48pub struct LintStore {
50 lints: Vec<&'static Lint>,
52
53 pub pre_expansion_passes: Vec<EarlyLintPassFactory>,
60 pub early_passes: Vec<EarlyLintPassFactory>,
61 pub late_passes: Vec<LateLintPassFactory>,
62 pub late_module_passes: Vec<LateLintPassFactory>,
64
65 by_name: UnordMap<String, TargetLint>,
67
68 lint_groups: FxIndexMap<&'static str, LintGroup>,
70}
71
72impl DynLintStore for LintStore {
73 fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = rustc_session::LintGroup> + '_> {
74 Box::new(self.get_lint_groups().map(|(name, lints, is_externally_loaded)| {
75 rustc_session::LintGroup { name, lints, is_externally_loaded }
76 }))
77 }
78}
79
80#[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)]
82enum TargetLint {
83 Id(LintId),
85
86 Renamed(String, LintId),
88
89 Removed(String),
92
93 Ignored,
98}
99
100struct LintAlias {
101 name: &'static str,
102 silent: bool,
104}
105
106struct LintGroup {
107 lint_ids: Vec<LintId>,
108 is_externally_loaded: bool,
109 depr: Option<LintAlias>,
110}
111
112#[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)]
113pub enum CheckLintNameResult<'a> {
114 Ok(&'a [LintId]),
115 NoLint(Option<(Symbol, bool)>),
117 NoTool,
119 Renamed(String),
121 Removed(String),
123
124 Tool(&'a [LintId], Option<String>),
128
129 MissingTool,
133}
134
135impl LintStore {
136 pub fn new() -> LintStore {
137 LintStore {
138 lints: ::alloc::vec::Vec::new()vec![],
139 pre_expansion_passes: ::alloc::vec::Vec::new()vec![],
140 early_passes: ::alloc::vec::Vec::new()vec![],
141 late_passes: ::alloc::vec::Vec::new()vec![],
142 late_module_passes: ::alloc::vec::Vec::new()vec![],
143 by_name: Default::default(),
144 lint_groups: Default::default(),
145 }
146 }
147
148 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
149 &self.lints
150 }
151
152 pub fn get_lint_groups(&self) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> {
153 self.lint_groups
154 .iter()
155 .filter(|(_, LintGroup { depr, .. })| {
156 depr.is_none()
158 })
159 .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
160 (*k, lint_ids.clone(), *is_externally_loaded)
161 })
162 }
163
164 pub fn get_all_group_names(&self) -> impl Iterator<Item = &'static str> {
166 self.lint_groups.keys().copied()
167 }
168
169 pub fn register_early_pass(&mut self, pass: EarlyLintPassFactory) {
170 self.early_passes.push(pass);
171 }
172
173 pub fn register_pre_expansion_pass(&mut self, pass: EarlyLintPassFactory) {
180 self.pre_expansion_passes.push(pass);
181 }
182
183 pub fn register_late_pass(&mut self, pass: LateLintPassFactory) {
184 self.late_passes.push(pass);
185 }
186
187 pub fn register_late_mod_pass(&mut self, pass: LateLintPassFactory) {
188 self.late_module_passes.push(pass);
189 }
190
191 pub fn register_lints(&mut self, lints: &[&'static Lint]) {
193 for lint in lints {
194 self.lints.push(lint);
195
196 let id = LintId::of(lint);
197 if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
198 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
lint.name_lower()))bug!("duplicate specification of lint {}", lint.name_lower())
199 }
200
201 if let Some(FutureIncompatibleInfo { reason, .. }) = lint.future_incompatible {
202 if let Some(edition) = reason.edition() {
203 self.lint_groups
204 .entry(edition.lint_name())
205 .or_insert(LintGroup {
206 lint_ids: ::alloc::vec::Vec::new()vec![],
207 is_externally_loaded: lint.is_externally_loaded,
208 depr: None,
209 })
210 .lint_ids
211 .push(id);
212 } else {
213 self.lint_groups
217 .entry("future_incompatible")
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 }
226 }
227 }
228 }
229
230 fn insert_group(&mut self, name: &'static str, group: LintGroup) {
231 let previous = self.lint_groups.insert(name, group);
232 if previous.is_some() {
233 ::rustc_middle::util::bug::bug_fmt(format_args!("group {0:?} already exists",
name));bug!("group {name:?} already exists");
234 }
235 }
236
237 pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) {
238 let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else {
239 ::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:?}")
240 };
241
242 self.insert_group(
243 alias,
244 LintGroup {
245 lint_ids: lint_ids.clone(),
246 is_externally_loaded: false,
247 depr: Some(LintAlias { name: group_name, silent: true }),
248 },
249 );
250 }
251
252 pub fn register_group(
253 &mut self,
254 is_externally_loaded: bool,
255 name: &'static str,
256 deprecated_name: Option<&'static str>,
257 to: Vec<LintId>,
258 ) {
259 if let Some(deprecated) = deprecated_name {
260 self.insert_group(
261 deprecated,
262 LintGroup {
263 lint_ids: to.clone(),
264 is_externally_loaded,
265 depr: Some(LintAlias { name, silent: false }),
266 },
267 );
268 }
269 self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None });
270 }
271
272 #[track_caller]
276 pub fn register_ignored(&mut self, name: &str) {
277 if self.by_name.insert(name.to_string(), Ignored).is_some() {
278 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
name));bug!("duplicate specification of lint {}", name);
279 }
280 }
281
282 #[track_caller]
284 pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
285 let Some(&Id(target)) = self.by_name.get(new_name) else {
286 ::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);
287 };
288 self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
289 }
290
291 pub fn register_removed(&mut self, name: &str, reason: &str) {
292 self.by_name.insert(name.into(), Removed(reason.into()));
293 }
294
295 pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
296 match self.by_name.get(lint_name) {
297 Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
298 Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)),
299 Some(Removed(_)) => None,
300 Some(Ignored) => Some(&[]),
301 None => match self.lint_groups.get(lint_name) {
302 Some(LintGroup { lint_ids, .. }) => Some(lint_ids),
303 None => None,
304 },
305 }
306 }
307
308 pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
310 {
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:310",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(310u32),
::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!(
311 "is_lint_group(lint_name={:?}, lint_groups={:?})",
312 lint_name,
313 self.lint_groups.keys().collect::<Vec<_>>()
314 );
315 let lint_name_str = lint_name.as_str();
316 self.lint_groups.contains_key(lint_name_str) || {
317 let warnings_name_str = crate::WARNINGS.name_lower();
318 lint_name_str == warnings_name_str
319 }
320 }
321
322 pub fn check_lint_name(
330 &self,
331 lint_name: &str,
332 tool_name: Option<Symbol>,
333 registered_tools: &RegisteredTools,
334 ) -> CheckLintNameResult<'_> {
335 if let Some(tool_name) = tool_name {
336 if tool_name != sym::rustc
338 && tool_name != sym::rustdoc
339 && !registered_tools.contains(&Ident::with_dummy_span(tool_name))
340 {
341 return CheckLintNameResult::NoTool;
342 }
343 }
344
345 let complete_name = if let Some(tool_name) = tool_name {
346 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}")
347 } else {
348 lint_name.to_string()
349 };
350 if let Some(tool_name) = tool_name {
352 match self.by_name.get(&complete_name) {
353 None => match self.lint_groups.get(&*complete_name) {
354 None => {
356 {
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:358",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(358u32),
::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);
359 let tool_prefix = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::", tool_name))
})format!("{tool_name}::");
360
361 return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
362 self.no_lint_suggestion(&complete_name, tool_name.as_str())
363 } else {
364 CheckLintNameResult::MissingTool
367 };
368 }
369 Some(LintGroup { lint_ids, depr, .. }) => {
370 return if let &Some(LintAlias { name, silent: false }) = depr {
371 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
372 } else {
373 CheckLintNameResult::Tool(lint_ids, None)
374 };
375 }
376 },
377 Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
378 _ => {}
381 }
382 }
383 match self.by_name.get(&complete_name) {
384 Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
385 Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
386 None => match self.lint_groups.get(&*complete_name) {
387 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
390 Some(LintGroup { lint_ids, depr, .. }) => {
391 if let &Some(LintAlias { name, silent: false }) = depr {
393 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
394 } else {
395 CheckLintNameResult::Ok(lint_ids)
396 }
397 }
398 },
399 Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
400 Some(&Ignored) => CheckLintNameResult::Ok(&[]),
401 }
402 }
403
404 fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
405 let name_lower = lint_name.to_lowercase();
406
407 if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() {
408 return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
410 }
411
412 #[allow(rustc::potential_query_instability)]
418 let mut groups: Vec<_> = self
419 .lint_groups
420 .iter()
421 .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k))
422 .collect();
423 groups.sort();
424 let groups = groups.iter().map(|k| Symbol::intern(k));
425 let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
426 let names: Vec<Symbol> = groups.chain(lints).collect();
427 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)];
428 if let Some(stripped) = name_lower.split("::").last() {
429 lookups.push(Symbol::intern(stripped));
430 }
431 let res = find_best_match_for_names(&names, &lookups, None);
432 let is_rustc = res.map_or_else(
433 || false,
434 |s| name_lower.contains("::") && !s.as_str().starts_with(tool_name),
435 );
436 let suggestion = res.map(|s| (s, is_rustc));
437 CheckLintNameResult::NoLint(suggestion)
438 }
439
440 fn check_tool_name_for_backwards_compat(
441 &self,
442 lint_name: &str,
443 tool_name: &str,
444 ) -> CheckLintNameResult<'_> {
445 let complete_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}");
446 match self.by_name.get(&complete_name) {
447 None => match self.lint_groups.get(&*complete_name) {
448 None => self.no_lint_suggestion(lint_name, tool_name),
450 Some(LintGroup { lint_ids, .. }) => {
451 CheckLintNameResult::Tool(lint_ids, Some(complete_name))
452 }
453 },
454 Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)),
455 Some(other) => {
456 {
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:456",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(456u32),
::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);
457 CheckLintNameResult::NoLint(None)
458 }
459 }
460 }
461}
462
463pub struct LateContext<'tcx> {
465 pub tcx: TyCtxt<'tcx>,
467
468 pub enclosing_body: Option<hir::BodyId>,
470
471 pub(super) cached_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
476
477 pub param_env: ty::ParamEnv<'tcx>,
479
480 pub effective_visibilities: &'tcx EffectiveVisibilities,
482
483 pub last_node_with_lint_attrs: hir::HirId,
484
485 pub generics: Option<&'tcx hir::Generics<'tcx>>,
487
488 pub only_module: bool,
490}
491
492pub struct EarlyContext<'a> {
494 pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>,
495 pub buffered: LintBuffer,
496}
497
498pub trait LintContext {
499 type LintExpectationId: Copy + Into<LintExpectationId>;
500
501 fn sess(&self) -> &Session;
502
503 #[track_caller]
509 fn opt_span_lint<S: Into<MultiSpan>>(
510 &self,
511 lint: &'static Lint,
512 span: Option<S>,
513 decorate: impl for<'a> Diagnostic<'a, ()>,
514 );
515
516 #[track_caller]
519 fn emit_span_lint<S: Into<MultiSpan>>(
520 &self,
521 lint: &'static Lint,
522 span: S,
523 decorator: impl for<'a> Diagnostic<'a, ()>,
524 ) {
525 self.opt_span_lint(lint, Some(span), decorator);
526 }
527
528 fn get_lint_level_spec(&self, lint: &'static Lint) -> LevelSpec<Self::LintExpectationId>;
530
531 fn fulfill_expectation(&self, expectation: Self::LintExpectationId) {
539 self.sess()
544 .dcx()
545 .struct_expect(
546 "this is a dummy diagnostic, to submit and store an expectation",
547 expectation.into(),
548 )
549 .emit();
550 }
551}
552
553impl<'a> EarlyContext<'a> {
554 pub(crate) fn new(
555 sess: &'a Session,
556 features: &'a Features,
557 lint_added_lints: bool,
558 lint_store: &'a LintStore,
559 registered_tools: &'a RegisteredTools,
560 buffered: LintBuffer,
561 ) -> EarlyContext<'a> {
562 EarlyContext {
563 builder: LintLevelsBuilder::new(
564 sess,
565 features,
566 lint_added_lints,
567 lint_store,
568 registered_tools,
569 ),
570 buffered,
571 }
572 }
573}
574
575impl<'tcx> LintContext for LateContext<'tcx> {
576 type LintExpectationId = StableLintExpectationId;
577
578 fn sess(&self) -> &Session {
580 self.tcx.sess
581 }
582
583 fn opt_span_lint<S: Into<MultiSpan>>(
584 &self,
585 lint: &'static Lint,
586 span: Option<S>,
587 decorate: impl for<'a> Diagnostic<'a, ()>,
588 ) {
589 let hir_id = self.last_node_with_lint_attrs;
590
591 match span {
592 Some(s) => self.tcx.emit_node_span_lint(lint, hir_id, s, decorate),
593 None => self.tcx.emit_node_lint(lint, hir_id, decorate),
594 }
595 }
596
597 fn get_lint_level_spec(&self, lint: &'static Lint) -> StableLevelSpec {
598 self.tcx.lint_level_spec_at_node(lint, self.last_node_with_lint_attrs)
599 }
600}
601
602impl LintContext for EarlyContext<'_> {
603 type LintExpectationId = UnstableLintExpectationId;
604
605 fn sess(&self) -> &Session {
607 self.builder.sess()
608 }
609
610 fn opt_span_lint<S: Into<MultiSpan>>(
611 &self,
612 lint: &'static Lint,
613 span: Option<S>,
614 decorator: impl for<'a> Diagnostic<'a, ()>,
615 ) {
616 self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorator)
617 }
618
619 fn get_lint_level_spec(&self, lint: &'static Lint) -> UnstableLevelSpec {
620 self.builder.lint_level_spec(lint)
621 }
622}
623
624impl<'tcx> LateContext<'tcx> {
625 pub fn typing_mode(&self) -> TypingMode<'tcx> {
628 if let Some(body_id) = self.enclosing_body
629 && self.tcx.use_typing_mode_post_typeck_until_borrowck()
630 {
631 let def_id = self.tcx.hir_enclosing_body_owner(body_id.hir_id);
632 TypingMode::borrowck(self.tcx, def_id)
633 } else {
634 TypingMode::non_body_analysis()
635 }
636 }
637
638 pub fn typing_env(&self) -> TypingEnv<'tcx> {
639 TypingEnv::new(self.param_env, self.typing_mode())
640 }
641
642 pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
643 self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
644 }
645
646 pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
647 self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
648 }
649
650 pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
653 self.cached_typeck_results.get().or_else(|| {
654 self.enclosing_body.map(|body| {
655 let typeck_results = self.tcx.typeck_body(body);
656 self.cached_typeck_results.set(Some(typeck_results));
657 typeck_results
658 })
659 })
660 }
661
662 #[track_caller]
666 pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
667 self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body")
668 }
669
670 pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
674 match *qpath {
675 hir::QPath::Resolved(_, path) => path.res,
676 hir::QPath::TypeRelative(..) => self
677 .maybe_typeck_results()
678 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
679 .or_else(|| {
680 self.tcx
681 .has_typeck_results(id.owner.def_id)
682 .then(|| self.tcx.typeck(id.owner.def_id))
683 })
684 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
685 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
686 }
687 }
688
689 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
709 struct LintPathPrinter<'tcx> {
710 tcx: TyCtxt<'tcx>,
711 path: Vec<Symbol>,
712 }
713
714 impl<'tcx> Printer<'tcx> for LintPathPrinter<'tcx> {
715 fn tcx(&self) -> TyCtxt<'tcx> {
716 self.tcx
717 }
718
719 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
720 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
722
723 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
724 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
726
727 fn print_dyn_existential(
728 &mut self,
729 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
730 ) -> Result<(), PrintError> {
731 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
733
734 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
735 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
737
738 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
739 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)];
740 Ok(())
741 }
742
743 fn print_path_with_qualified(
744 &mut self,
745 self_ty: Ty<'tcx>,
746 trait_ref: Option<ty::TraitRef<'tcx>>,
747 ) -> Result<(), PrintError> {
748 if trait_ref.is_none()
749 && let ty::Adt(def, args) = self_ty.kind()
750 {
751 return self.print_def_path(def.did(), args);
752 }
753
754 {
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!({
756 self.path = vec![match trait_ref {
757 Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
758 None => Symbol::intern(&format!("<{self_ty}>")),
759 }];
760 Ok(())
761 })
762 }
763
764 fn print_path_with_impl(
765 &mut self,
766 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
767 self_ty: Ty<'tcx>,
768 trait_ref: Option<ty::TraitRef<'tcx>>,
769 ) -> Result<(), PrintError> {
770 print_prefix(self)?;
771
772 self.path.push(match trait_ref {
774 Some(trait_ref) => {
775 {
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!(
776 "<impl {} for {}>",
777 trait_ref.print_only_trait_path(),
778 self_ty
779 )))
780 }
781 None => {
782 {
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}>")))
783 }
784 });
785
786 Ok(())
787 }
788
789 fn print_path_with_simple(
790 &mut self,
791 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
792 disambiguated_data: &DisambiguatedDefPathData,
793 ) -> Result<(), PrintError> {
794 print_prefix(self)?;
795
796 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
798 return Ok(());
799 }
800
801 self.path.push(match disambiguated_data.data.get_opt_name() {
802 Some(sym) => sym,
803 None => Symbol::intern(&disambiguated_data.data.to_string()),
804 });
805 Ok(())
806 }
807
808 fn print_path_with_generic_args(
809 &mut self,
810 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
811 _args: &[GenericArg<'tcx>],
812 ) -> Result<(), PrintError> {
813 print_prefix(self)
814 }
815 }
816
817 let mut p = LintPathPrinter { tcx: self.tcx, path: ::alloc::vec::Vec::new()vec![] };
818 p.print_def_path(def_id, &[]).unwrap();
819 p.path
820 }
821
822 pub fn get_associated_type(
825 &self,
826 self_ty: Ty<'tcx>,
827 trait_id: DefId,
828 name: Symbol,
829 ) -> Option<Ty<'tcx>> {
830 let tcx = self.tcx;
831 tcx.associated_items(trait_id)
832 .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
833 .and_then(|assoc| {
834 let proj = Ty::new_projection(tcx, ty::IsRigid::No, assoc.def_id, [self_ty]);
835 tcx.try_normalize_erasing_regions(self.typing_env(), Unnormalized::new_wip(proj))
836 .ok()
837 })
838 }
839
840 pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
844 let has_attr = |id: hir::HirId| -> bool {
845 self.tcx.hir_attrs(id).iter().any(hir::Attribute::is_prefix_attr_for_suggestions)
846 };
847 expr.precedence(&has_attr)
848 }
849
850 pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
866 expr = expr.peel_blocks();
867
868 while let hir::ExprKind::Path(ref qpath) = expr.kind
869 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
870 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
871 _ => None,
872 }
873 && let Some(init) = match parent_node {
874 hir::Node::Expr(expr) => Some(expr),
875 hir::Node::LetStmt(hir::LetStmt {
876 init,
877 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
879 ..
880 }) => *init,
881 _ => None,
882 }
883 {
884 expr = init.peel_blocks();
885 }
886 expr
887 }
888
889 pub fn expr_or_init_with_outside_body<'a>(
912 &self,
913 mut expr: &'a hir::Expr<'tcx>,
914 ) -> &'a hir::Expr<'tcx> {
915 expr = expr.peel_blocks();
916
917 while let hir::ExprKind::Path(ref qpath) = expr.kind
918 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
919 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
920 Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
921 _ => None,
922 }
923 && let Some(init) = match parent_node {
924 hir::Node::Expr(expr) => Some(expr),
925 hir::Node::LetStmt(hir::LetStmt {
926 init,
927 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
929 ..
930 }) => *init,
931 hir::Node::Item(item) => match item.kind {
932 hir::ItemKind::Const(.., hir::ConstItemRhs::Body(body_id))
934 | hir::ItemKind::Static(.., body_id) => Some(self.tcx.hir_body(body_id).value),
935 _ => None,
936 },
937 _ => None,
938 }
939 {
940 expr = init.peel_blocks();
941 }
942 expr
943 }
944}
945
946impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
947 #[inline]
948 fn data_layout(&self) -> &abi::TargetDataLayout {
949 &self.tcx.data_layout
950 }
951}
952
953impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
954 #[inline]
955 fn tcx(&self) -> TyCtxt<'tcx> {
956 self.tcx
957 }
958}
959
960impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
961 #[inline]
962 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
963 self.typing_env()
964 }
965}
966
967impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
968 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
969
970 #[inline]
971 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
972 err
973 }
974}