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::{
28 self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode, Unnormalized,
29};
30use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintExpectationId, LintId};
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
76#[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)]
78enum TargetLint {
79 Id(LintId),
81
82 Renamed(String, LintId),
84
85 Removed(String),
88
89 Ignored,
94}
95
96struct LintAlias {
97 name: &'static str,
98 silent: bool,
100}
101
102struct LintGroup {
103 lint_ids: Vec<LintId>,
104 is_externally_loaded: bool,
105 depr: Option<LintAlias>,
106}
107
108#[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)]
109pub enum CheckLintNameResult<'a> {
110 Ok(&'a [LintId]),
111 NoLint(Option<(Symbol, bool)>),
113 NoTool,
115 Renamed(String),
117 Removed(String),
119
120 Tool(&'a [LintId], Option<String>),
124
125 MissingTool,
129}
130
131impl LintStore {
132 pub fn new() -> LintStore {
133 LintStore {
134 lints: ::alloc::vec::Vec::new()vec![],
135 pre_expansion_passes: ::alloc::vec::Vec::new()vec![],
136 early_passes: ::alloc::vec::Vec::new()vec![],
137 late_passes: ::alloc::vec::Vec::new()vec![],
138 late_module_passes: ::alloc::vec::Vec::new()vec![],
139 by_name: Default::default(),
140 lint_groups: Default::default(),
141 }
142 }
143
144 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
145 &self.lints
146 }
147
148 pub fn get_lint_groups(&self) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> {
149 self.lint_groups
150 .iter()
151 .filter(|(_, LintGroup { depr, .. })| {
152 depr.is_none()
154 })
155 .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
156 (*k, lint_ids.clone(), *is_externally_loaded)
157 })
158 }
159
160 pub fn get_all_group_names(&self) -> impl Iterator<Item = &'static str> {
162 self.lint_groups.keys().copied()
163 }
164
165 pub fn register_early_pass(
166 &mut self,
167 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
168 ) {
169 self.early_passes.push(Box::new(pass));
170 }
171
172 pub fn register_pre_expansion_pass(
179 &mut self,
180 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
181 ) {
182 self.pre_expansion_passes.push(Box::new(pass));
183 }
184
185 pub fn register_late_pass(
186 &mut self,
187 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
188 + 'static
189 + sync::DynSend
190 + sync::DynSync,
191 ) {
192 self.late_passes.push(Box::new(pass));
193 }
194
195 pub fn register_late_mod_pass(
196 &mut self,
197 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
198 + 'static
199 + sync::DynSend
200 + sync::DynSync,
201 ) {
202 self.late_module_passes.push(Box::new(pass));
203 }
204
205 pub fn register_lints(&mut self, lints: &[&'static Lint]) {
207 for lint in lints {
208 self.lints.push(lint);
209
210 let id = LintId::of(lint);
211 if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
212 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
lint.name_lower()))bug!("duplicate specification of lint {}", lint.name_lower())
213 }
214
215 if let Some(FutureIncompatibleInfo { reason, .. }) = lint.future_incompatible {
216 if let Some(edition) = reason.edition() {
217 self.lint_groups
218 .entry(edition.lint_name())
219 .or_insert(LintGroup {
220 lint_ids: ::alloc::vec::Vec::new()vec![],
221 is_externally_loaded: lint.is_externally_loaded,
222 depr: None,
223 })
224 .lint_ids
225 .push(id);
226 } else {
227 self.lint_groups
231 .entry("future_incompatible")
232 .or_insert(LintGroup {
233 lint_ids: ::alloc::vec::Vec::new()vec![],
234 is_externally_loaded: lint.is_externally_loaded,
235 depr: None,
236 })
237 .lint_ids
238 .push(id);
239 }
240 }
241 }
242 }
243
244 fn insert_group(&mut self, name: &'static str, group: LintGroup) {
245 let previous = self.lint_groups.insert(name, group);
246 if previous.is_some() {
247 ::rustc_middle::util::bug::bug_fmt(format_args!("group {0:?} already exists",
name));bug!("group {name:?} already exists");
248 }
249 }
250
251 pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) {
252 let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else {
253 ::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:?}")
254 };
255
256 self.insert_group(
257 alias,
258 LintGroup {
259 lint_ids: lint_ids.clone(),
260 is_externally_loaded: false,
261 depr: Some(LintAlias { name: group_name, silent: true }),
262 },
263 );
264 }
265
266 pub fn register_group(
267 &mut self,
268 is_externally_loaded: bool,
269 name: &'static str,
270 deprecated_name: Option<&'static str>,
271 to: Vec<LintId>,
272 ) {
273 if let Some(deprecated) = deprecated_name {
274 self.insert_group(
275 deprecated,
276 LintGroup {
277 lint_ids: to.clone(),
278 is_externally_loaded,
279 depr: Some(LintAlias { name, silent: false }),
280 },
281 );
282 }
283 self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None });
284 }
285
286 #[track_caller]
290 pub fn register_ignored(&mut self, name: &str) {
291 if self.by_name.insert(name.to_string(), Ignored).is_some() {
292 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
name));bug!("duplicate specification of lint {}", name);
293 }
294 }
295
296 #[track_caller]
298 pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
299 let Some(&Id(target)) = self.by_name.get(new_name) else {
300 ::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);
301 };
302 self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
303 }
304
305 pub fn register_removed(&mut self, name: &str, reason: &str) {
306 self.by_name.insert(name.into(), Removed(reason.into()));
307 }
308
309 pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
310 match self.by_name.get(lint_name) {
311 Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
312 Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)),
313 Some(Removed(_)) => None,
314 Some(Ignored) => Some(&[]),
315 None => match self.lint_groups.get(lint_name) {
316 Some(LintGroup { lint_ids, .. }) => Some(lint_ids),
317 None => None,
318 },
319 }
320 }
321
322 pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
324 {
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:324",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(324u32),
::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!(
325 "is_lint_group(lint_name={:?}, lint_groups={:?})",
326 lint_name,
327 self.lint_groups.keys().collect::<Vec<_>>()
328 );
329 let lint_name_str = lint_name.as_str();
330 self.lint_groups.contains_key(lint_name_str) || {
331 let warnings_name_str = crate::WARNINGS.name_lower();
332 lint_name_str == warnings_name_str
333 }
334 }
335
336 pub fn check_lint_name(
344 &self,
345 lint_name: &str,
346 tool_name: Option<Symbol>,
347 registered_tools: &RegisteredTools,
348 ) -> CheckLintNameResult<'_> {
349 if let Some(tool_name) = tool_name {
350 if tool_name != sym::rustc
352 && tool_name != sym::rustdoc
353 && !registered_tools.contains(&Ident::with_dummy_span(tool_name))
354 {
355 return CheckLintNameResult::NoTool;
356 }
357 }
358
359 let complete_name = if let Some(tool_name) = tool_name {
360 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}")
361 } else {
362 lint_name.to_string()
363 };
364 if let Some(tool_name) = tool_name {
366 match self.by_name.get(&complete_name) {
367 None => match self.lint_groups.get(&*complete_name) {
368 None => {
370 {
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:372",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(372u32),
::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);
373 let tool_prefix = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::", tool_name))
})format!("{tool_name}::");
374
375 return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
376 self.no_lint_suggestion(&complete_name, tool_name.as_str())
377 } else {
378 CheckLintNameResult::MissingTool
381 };
382 }
383 Some(LintGroup { lint_ids, depr, .. }) => {
384 return if let &Some(LintAlias { name, silent: false }) = depr {
385 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
386 } else {
387 CheckLintNameResult::Tool(lint_ids, None)
388 };
389 }
390 },
391 Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
392 _ => {}
395 }
396 }
397 match self.by_name.get(&complete_name) {
398 Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
399 Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
400 None => match self.lint_groups.get(&*complete_name) {
401 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
404 Some(LintGroup { lint_ids, depr, .. }) => {
405 if let &Some(LintAlias { name, silent: false }) = depr {
407 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
408 } else {
409 CheckLintNameResult::Ok(lint_ids)
410 }
411 }
412 },
413 Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
414 Some(&Ignored) => CheckLintNameResult::Ok(&[]),
415 }
416 }
417
418 fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
419 let name_lower = lint_name.to_lowercase();
420
421 if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() {
422 return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
424 }
425
426 #[allow(rustc::potential_query_instability)]
432 let mut groups: Vec<_> = self
433 .lint_groups
434 .iter()
435 .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k))
436 .collect();
437 groups.sort();
438 let groups = groups.iter().map(|k| Symbol::intern(k));
439 let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
440 let names: Vec<Symbol> = groups.chain(lints).collect();
441 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)];
442 if let Some(stripped) = name_lower.split("::").last() {
443 lookups.push(Symbol::intern(stripped));
444 }
445 let res = find_best_match_for_names(&names, &lookups, None);
446 let is_rustc = res.map_or_else(
447 || false,
448 |s| name_lower.contains("::") && !s.as_str().starts_with(tool_name),
449 );
450 let suggestion = res.map(|s| (s, is_rustc));
451 CheckLintNameResult::NoLint(suggestion)
452 }
453
454 fn check_tool_name_for_backwards_compat(
455 &self,
456 lint_name: &str,
457 tool_name: &str,
458 ) -> CheckLintNameResult<'_> {
459 let complete_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}");
460 match self.by_name.get(&complete_name) {
461 None => match self.lint_groups.get(&*complete_name) {
462 None => self.no_lint_suggestion(lint_name, tool_name),
464 Some(LintGroup { lint_ids, .. }) => {
465 CheckLintNameResult::Tool(lint_ids, Some(complete_name))
466 }
467 },
468 Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)),
469 Some(other) => {
470 {
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:470",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(470u32),
::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);
471 CheckLintNameResult::NoLint(None)
472 }
473 }
474 }
475}
476
477pub struct LateContext<'tcx> {
479 pub tcx: TyCtxt<'tcx>,
481
482 pub enclosing_body: Option<hir::BodyId>,
484
485 pub(super) cached_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
490
491 pub param_env: ty::ParamEnv<'tcx>,
493
494 pub effective_visibilities: &'tcx EffectiveVisibilities,
496
497 pub last_node_with_lint_attrs: hir::HirId,
498
499 pub generics: Option<&'tcx hir::Generics<'tcx>>,
501
502 pub only_module: bool,
504}
505
506pub struct EarlyContext<'a> {
508 pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>,
509 pub buffered: LintBuffer,
510}
511
512pub trait LintContext {
513 fn sess(&self) -> &Session;
514
515 #[track_caller]
521 fn opt_span_lint<S: Into<MultiSpan>>(
522 &self,
523 lint: &'static Lint,
524 span: Option<S>,
525 decorate: impl for<'a> Diagnostic<'a, ()>,
526 );
527
528 #[track_caller]
531 fn emit_span_lint<S: Into<MultiSpan>>(
532 &self,
533 lint: &'static Lint,
534 span: S,
535 decorator: impl for<'a> Diagnostic<'a, ()>,
536 ) {
537 self.opt_span_lint(lint, Some(span), decorator);
538 }
539
540 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource;
542
543 fn fulfill_expectation(&self, expectation: LintExpectationId) {
551 self.sess()
556 .dcx()
557 .struct_expect(
558 "this is a dummy diagnostic, to submit and store an expectation",
559 expectation,
560 )
561 .emit();
562 }
563}
564
565impl<'a> EarlyContext<'a> {
566 pub(crate) fn new(
567 sess: &'a Session,
568 features: &'a Features,
569 lint_added_lints: bool,
570 lint_store: &'a LintStore,
571 registered_tools: &'a RegisteredTools,
572 buffered: LintBuffer,
573 ) -> EarlyContext<'a> {
574 EarlyContext {
575 builder: LintLevelsBuilder::new(
576 sess,
577 features,
578 lint_added_lints,
579 lint_store,
580 registered_tools,
581 ),
582 buffered,
583 }
584 }
585}
586
587impl<'tcx> LintContext for LateContext<'tcx> {
588 fn sess(&self) -> &Session {
590 self.tcx.sess
591 }
592
593 fn opt_span_lint<S: Into<MultiSpan>>(
594 &self,
595 lint: &'static Lint,
596 span: Option<S>,
597 decorate: impl for<'a> Diagnostic<'a, ()>,
598 ) {
599 let hir_id = self.last_node_with_lint_attrs;
600
601 match span {
602 Some(s) => self.tcx.emit_node_span_lint(lint, hir_id, s, decorate),
603 None => self.tcx.emit_node_lint(lint, hir_id, decorate),
604 }
605 }
606
607 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
608 self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs)
609 }
610}
611
612impl LintContext for EarlyContext<'_> {
613 fn sess(&self) -> &Session {
615 self.builder.sess()
616 }
617
618 fn opt_span_lint<S: Into<MultiSpan>>(
619 &self,
620 lint: &'static Lint,
621 span: Option<S>,
622 decorator: impl for<'a> Diagnostic<'a, ()>,
623 ) {
624 self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorator)
625 }
626
627 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
628 self.builder.lint_level(lint)
629 }
630}
631
632impl<'tcx> LateContext<'tcx> {
633 pub fn typing_mode(&self) -> TypingMode<'tcx> {
636 TypingMode::non_body_analysis()
639 }
640
641 pub fn typing_env(&self) -> TypingEnv<'tcx> {
642 TypingEnv::new(self.param_env, self.typing_mode())
643 }
644
645 pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
646 self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
647 }
648
649 pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
650 self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
651 }
652
653 pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
656 self.cached_typeck_results.get().or_else(|| {
657 self.enclosing_body.map(|body| {
658 let typeck_results = self.tcx.typeck_body(body);
659 self.cached_typeck_results.set(Some(typeck_results));
660 typeck_results
661 })
662 })
663 }
664
665 #[track_caller]
669 pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
670 self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body")
671 }
672
673 pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
677 match *qpath {
678 hir::QPath::Resolved(_, path) => path.res,
679 hir::QPath::TypeRelative(..) => self
680 .maybe_typeck_results()
681 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
682 .or_else(|| {
683 self.tcx
684 .has_typeck_results(id.owner.def_id)
685 .then(|| self.tcx.typeck(id.owner.def_id))
686 })
687 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
688 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
689 }
690 }
691
692 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
712 struct LintPathPrinter<'tcx> {
713 tcx: TyCtxt<'tcx>,
714 path: Vec<Symbol>,
715 }
716
717 impl<'tcx> Printer<'tcx> for LintPathPrinter<'tcx> {
718 fn tcx(&self) -> TyCtxt<'tcx> {
719 self.tcx
720 }
721
722 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
723 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
725
726 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
727 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
729
730 fn print_dyn_existential(
731 &mut self,
732 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
733 ) -> Result<(), PrintError> {
734 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
736
737 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
738 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
740
741 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
742 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)];
743 Ok(())
744 }
745
746 fn print_path_with_qualified(
747 &mut self,
748 self_ty: Ty<'tcx>,
749 trait_ref: Option<ty::TraitRef<'tcx>>,
750 ) -> Result<(), PrintError> {
751 if trait_ref.is_none()
752 && let ty::Adt(def, args) = self_ty.kind()
753 {
754 return self.print_def_path(def.did(), args);
755 }
756
757 {
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!({
759 self.path = vec![match trait_ref {
760 Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
761 None => Symbol::intern(&format!("<{self_ty}>")),
762 }];
763 Ok(())
764 })
765 }
766
767 fn print_path_with_impl(
768 &mut self,
769 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
770 self_ty: Ty<'tcx>,
771 trait_ref: Option<ty::TraitRef<'tcx>>,
772 ) -> Result<(), PrintError> {
773 print_prefix(self)?;
774
775 self.path.push(match trait_ref {
777 Some(trait_ref) => {
778 {
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!(
779 "<impl {} for {}>",
780 trait_ref.print_only_trait_path(),
781 self_ty
782 )))
783 }
784 None => {
785 {
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}>")))
786 }
787 });
788
789 Ok(())
790 }
791
792 fn print_path_with_simple(
793 &mut self,
794 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
795 disambiguated_data: &DisambiguatedDefPathData,
796 ) -> Result<(), PrintError> {
797 print_prefix(self)?;
798
799 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
801 return Ok(());
802 }
803
804 self.path.push(match disambiguated_data.data.get_opt_name() {
805 Some(sym) => sym,
806 None => Symbol::intern(&disambiguated_data.data.to_string()),
807 });
808 Ok(())
809 }
810
811 fn print_path_with_generic_args(
812 &mut self,
813 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
814 _args: &[GenericArg<'tcx>],
815 ) -> Result<(), PrintError> {
816 print_prefix(self)
817 }
818 }
819
820 let mut p = LintPathPrinter { tcx: self.tcx, path: ::alloc::vec::Vec::new()vec![] };
821 p.print_def_path(def_id, &[]).unwrap();
822 p.path
823 }
824
825 pub fn get_associated_type(
828 &self,
829 self_ty: Ty<'tcx>,
830 trait_id: DefId,
831 name: Symbol,
832 ) -> Option<Ty<'tcx>> {
833 let tcx = self.tcx;
834 tcx.associated_items(trait_id)
835 .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
836 .and_then(|assoc| {
837 let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
838 tcx.try_normalize_erasing_regions(self.typing_env(), Unnormalized::new_wip(proj))
839 .ok()
840 })
841 }
842
843 pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
847 let has_attr = |id: hir::HirId| -> bool {
848 self.tcx.hir_attrs(id).iter().any(hir::Attribute::is_prefix_attr_for_suggestions)
849 };
850 expr.precedence(&has_attr)
851 }
852
853 pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
869 expr = expr.peel_blocks();
870
871 while let hir::ExprKind::Path(ref qpath) = expr.kind
872 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
873 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
874 _ => None,
875 }
876 && let Some(init) = match parent_node {
877 hir::Node::Expr(expr) => Some(expr),
878 hir::Node::LetStmt(hir::LetStmt {
879 init,
880 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
882 ..
883 }) => *init,
884 _ => None,
885 }
886 {
887 expr = init.peel_blocks();
888 }
889 expr
890 }
891
892 pub fn expr_or_init_with_outside_body<'a>(
915 &self,
916 mut expr: &'a hir::Expr<'tcx>,
917 ) -> &'a hir::Expr<'tcx> {
918 expr = expr.peel_blocks();
919
920 while let hir::ExprKind::Path(ref qpath) = expr.kind
921 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
922 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
923 Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
924 _ => None,
925 }
926 && let Some(init) = match parent_node {
927 hir::Node::Expr(expr) => Some(expr),
928 hir::Node::LetStmt(hir::LetStmt {
929 init,
930 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
932 ..
933 }) => *init,
934 hir::Node::Item(item) => match item.kind {
935 hir::ItemKind::Const(.., hir::ConstItemRhs::Body(body_id))
937 | hir::ItemKind::Static(.., body_id) => Some(self.tcx.hir_body(body_id).value),
938 _ => None,
939 },
940 _ => None,
941 }
942 {
943 expr = init.peel_blocks();
944 }
945 expr
946 }
947}
948
949impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
950 #[inline]
951 fn data_layout(&self) -> &abi::TargetDataLayout {
952 &self.tcx.data_layout
953 }
954}
955
956impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
957 #[inline]
958 fn tcx(&self) -> TyCtxt<'tcx> {
959 self.tcx
960 }
961}
962
963impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
964 #[inline]
965 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
966 self.typing_env()
967 }
968}
969
970impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
971 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
972
973 #[inline]
974 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
975 err
976 }
977}