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::{FutureIncompatibleInfo, Lint, LintExpectationId, LintId};
29use rustc_session::{DynLintStore, Session};
30use rustc_span::edit_distance::find_best_match_for_names;
31use rustc_span::{Ident, Span, Symbol, sym};
32use tracing::debug;
33
34use self::TargetLint::*;
35use crate::levels::LintLevelsBuilder;
36use crate::passes::{EarlyLintPassObject, LateLintPassObject};
37
38type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync;
39type LateLintPassFactory =
40 dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
41
42pub struct LintStore {
44 lints: Vec<&'static Lint>,
46
47 pub pre_expansion_passes: Vec<Box<EarlyLintPassFactory>>,
54 pub early_passes: Vec<Box<EarlyLintPassFactory>>,
55 pub late_passes: Vec<Box<LateLintPassFactory>>,
56 pub late_module_passes: Vec<Box<LateLintPassFactory>>,
58
59 by_name: UnordMap<String, TargetLint>,
61
62 lint_groups: FxIndexMap<&'static str, LintGroup>,
64}
65
66impl DynLintStore for LintStore {
67 fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = rustc_session::LintGroup> + '_> {
68 Box::new(self.get_lint_groups().map(|(name, lints, is_externally_loaded)| {
69 rustc_session::LintGroup { name, lints, is_externally_loaded }
70 }))
71 }
72}
73
74#[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)]
76enum TargetLint {
77 Id(LintId),
79
80 Renamed(String, LintId),
82
83 Removed(String),
86
87 Ignored,
92}
93
94struct LintAlias {
95 name: &'static str,
96 silent: bool,
98}
99
100struct LintGroup {
101 lint_ids: Vec<LintId>,
102 is_externally_loaded: bool,
103 depr: Option<LintAlias>,
104}
105
106#[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)]
107pub enum CheckLintNameResult<'a> {
108 Ok(&'a [LintId]),
109 NoLint(Option<(Symbol, bool)>),
111 NoTool,
113 Renamed(String),
115 Removed(String),
117
118 Tool(&'a [LintId], Option<String>),
122
123 MissingTool,
127}
128
129impl LintStore {
130 pub fn new() -> LintStore {
131 LintStore {
132 lints: ::alloc::vec::Vec::new()vec![],
133 pre_expansion_passes: ::alloc::vec::Vec::new()vec![],
134 early_passes: ::alloc::vec::Vec::new()vec![],
135 late_passes: ::alloc::vec::Vec::new()vec![],
136 late_module_passes: ::alloc::vec::Vec::new()vec![],
137 by_name: Default::default(),
138 lint_groups: Default::default(),
139 }
140 }
141
142 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
143 &self.lints
144 }
145
146 pub fn get_lint_groups(&self) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> {
147 self.lint_groups
148 .iter()
149 .filter(|(_, LintGroup { depr, .. })| {
150 depr.is_none()
152 })
153 .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
154 (*k, lint_ids.clone(), *is_externally_loaded)
155 })
156 }
157
158 pub fn get_all_group_names(&self) -> impl Iterator<Item = &'static str> {
160 self.lint_groups.keys().copied()
161 }
162
163 pub fn register_early_pass(
164 &mut self,
165 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
166 ) {
167 self.early_passes.push(Box::new(pass));
168 }
169
170 pub fn register_pre_expansion_pass(
177 &mut self,
178 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
179 ) {
180 self.pre_expansion_passes.push(Box::new(pass));
181 }
182
183 pub fn register_late_pass(
184 &mut self,
185 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
186 + 'static
187 + sync::DynSend
188 + sync::DynSync,
189 ) {
190 self.late_passes.push(Box::new(pass));
191 }
192
193 pub fn register_late_mod_pass(
194 &mut self,
195 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
196 + 'static
197 + sync::DynSend
198 + sync::DynSync,
199 ) {
200 self.late_module_passes.push(Box::new(pass));
201 }
202
203 pub fn register_lints(&mut self, lints: &[&'static Lint]) {
205 for lint in lints {
206 self.lints.push(lint);
207
208 let id = LintId::of(lint);
209 if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
210 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
lint.name_lower()))bug!("duplicate specification of lint {}", lint.name_lower())
211 }
212
213 if let Some(FutureIncompatibleInfo { reason, .. }) = lint.future_incompatible {
214 if let Some(edition) = reason.edition() {
215 self.lint_groups
216 .entry(edition.lint_name())
217 .or_insert(LintGroup {
218 lint_ids: ::alloc::vec::Vec::new()vec![],
219 is_externally_loaded: lint.is_externally_loaded,
220 depr: None,
221 })
222 .lint_ids
223 .push(id);
224 } else {
225 self.lint_groups
229 .entry("future_incompatible")
230 .or_insert(LintGroup {
231 lint_ids: ::alloc::vec::Vec::new()vec![],
232 is_externally_loaded: lint.is_externally_loaded,
233 depr: None,
234 })
235 .lint_ids
236 .push(id);
237 }
238 }
239 }
240 }
241
242 fn insert_group(&mut self, name: &'static str, group: LintGroup) {
243 let previous = self.lint_groups.insert(name, group);
244 if previous.is_some() {
245 ::rustc_middle::util::bug::bug_fmt(format_args!("group {0:?} already exists",
name));bug!("group {name:?} already exists");
246 }
247 }
248
249 pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) {
250 let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else {
251 ::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:?}")
252 };
253
254 self.insert_group(
255 alias,
256 LintGroup {
257 lint_ids: lint_ids.clone(),
258 is_externally_loaded: false,
259 depr: Some(LintAlias { name: group_name, silent: true }),
260 },
261 );
262 }
263
264 pub fn register_group(
265 &mut self,
266 is_externally_loaded: bool,
267 name: &'static str,
268 deprecated_name: Option<&'static str>,
269 to: Vec<LintId>,
270 ) {
271 if let Some(deprecated) = deprecated_name {
272 self.insert_group(
273 deprecated,
274 LintGroup {
275 lint_ids: to.clone(),
276 is_externally_loaded,
277 depr: Some(LintAlias { name, silent: false }),
278 },
279 );
280 }
281 self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None });
282 }
283
284 #[track_caller]
288 pub fn register_ignored(&mut self, name: &str) {
289 if self.by_name.insert(name.to_string(), Ignored).is_some() {
290 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
name));bug!("duplicate specification of lint {}", name);
291 }
292 }
293
294 #[track_caller]
296 pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
297 let Some(&Id(target)) = self.by_name.get(new_name) else {
298 ::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);
299 };
300 self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
301 }
302
303 pub fn register_removed(&mut self, name: &str, reason: &str) {
304 self.by_name.insert(name.into(), Removed(reason.into()));
305 }
306
307 pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
308 match self.by_name.get(lint_name) {
309 Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
310 Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)),
311 Some(Removed(_)) => None,
312 Some(Ignored) => Some(&[]),
313 None => match self.lint_groups.get(lint_name) {
314 Some(LintGroup { lint_ids, .. }) => Some(lint_ids),
315 None => None,
316 },
317 }
318 }
319
320 pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
322 {
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:322",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(322u32),
::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!(
323 "is_lint_group(lint_name={:?}, lint_groups={:?})",
324 lint_name,
325 self.lint_groups.keys().collect::<Vec<_>>()
326 );
327 let lint_name_str = lint_name.as_str();
328 self.lint_groups.contains_key(lint_name_str) || {
329 let warnings_name_str = crate::WARNINGS.name_lower();
330 lint_name_str == warnings_name_str
331 }
332 }
333
334 pub fn check_lint_name(
342 &self,
343 lint_name: &str,
344 tool_name: Option<Symbol>,
345 registered_tools: &RegisteredTools,
346 ) -> CheckLintNameResult<'_> {
347 if let Some(tool_name) = tool_name {
348 if tool_name != sym::rustc
350 && tool_name != sym::rustdoc
351 && !registered_tools.contains(&Ident::with_dummy_span(tool_name))
352 {
353 return CheckLintNameResult::NoTool;
354 }
355 }
356
357 let complete_name = if let Some(tool_name) = tool_name {
358 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}")
359 } else {
360 lint_name.to_string()
361 };
362 if let Some(tool_name) = tool_name {
364 match self.by_name.get(&complete_name) {
365 None => match self.lint_groups.get(&*complete_name) {
366 None => {
368 {
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:370",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(370u32),
::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);
371 let tool_prefix = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::", tool_name))
})format!("{tool_name}::");
372
373 return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
374 self.no_lint_suggestion(&complete_name, tool_name.as_str())
375 } else {
376 CheckLintNameResult::MissingTool
379 };
380 }
381 Some(LintGroup { lint_ids, depr, .. }) => {
382 return if let &Some(LintAlias { name, silent: false }) = depr {
383 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
384 } else {
385 CheckLintNameResult::Tool(lint_ids, None)
386 };
387 }
388 },
389 Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
390 _ => {}
393 }
394 }
395 match self.by_name.get(&complete_name) {
396 Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
397 Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
398 None => match self.lint_groups.get(&*complete_name) {
399 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
402 Some(LintGroup { lint_ids, depr, .. }) => {
403 if let &Some(LintAlias { name, silent: false }) = depr {
405 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
406 } else {
407 CheckLintNameResult::Ok(lint_ids)
408 }
409 }
410 },
411 Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
412 Some(&Ignored) => CheckLintNameResult::Ok(&[]),
413 }
414 }
415
416 fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
417 let name_lower = lint_name.to_lowercase();
418
419 if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() {
420 return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
422 }
423
424 #[allow(rustc::potential_query_instability)]
430 let mut groups: Vec<_> = self
431 .lint_groups
432 .iter()
433 .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k))
434 .collect();
435 groups.sort();
436 let groups = groups.iter().map(|k| Symbol::intern(k));
437 let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
438 let names: Vec<Symbol> = groups.chain(lints).collect();
439 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)];
440 if let Some(stripped) = name_lower.split("::").last() {
441 lookups.push(Symbol::intern(stripped));
442 }
443 let res = find_best_match_for_names(&names, &lookups, None);
444 let is_rustc = res.map_or_else(
445 || false,
446 |s| name_lower.contains("::") && !s.as_str().starts_with(tool_name),
447 );
448 let suggestion = res.map(|s| (s, is_rustc));
449 CheckLintNameResult::NoLint(suggestion)
450 }
451
452 fn check_tool_name_for_backwards_compat(
453 &self,
454 lint_name: &str,
455 tool_name: &str,
456 ) -> CheckLintNameResult<'_> {
457 let complete_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}");
458 match self.by_name.get(&complete_name) {
459 None => match self.lint_groups.get(&*complete_name) {
460 None => self.no_lint_suggestion(lint_name, tool_name),
462 Some(LintGroup { lint_ids, .. }) => {
463 CheckLintNameResult::Tool(lint_ids, Some(complete_name))
464 }
465 },
466 Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)),
467 Some(other) => {
468 {
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:468",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(468u32),
::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);
469 CheckLintNameResult::NoLint(None)
470 }
471 }
472 }
473}
474
475pub struct LateContext<'tcx> {
477 pub tcx: TyCtxt<'tcx>,
479
480 pub enclosing_body: Option<hir::BodyId>,
482
483 pub(super) cached_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
488
489 pub param_env: ty::ParamEnv<'tcx>,
491
492 pub effective_visibilities: &'tcx EffectiveVisibilities,
494
495 pub last_node_with_lint_attrs: hir::HirId,
496
497 pub generics: Option<&'tcx hir::Generics<'tcx>>,
499
500 pub only_module: bool,
502}
503
504pub struct EarlyContext<'a> {
506 pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>,
507 pub buffered: LintBuffer,
508}
509
510pub trait LintContext {
511 fn sess(&self) -> &Session;
512
513 #[track_caller]
519 fn opt_span_diag_lint<S: Into<MultiSpan>>(
520 &self,
521 lint: &'static Lint,
522 span: Option<S>,
523 decorate: impl for<'a> Diagnostic<'a, ()>,
524 );
525
526 #[track_caller]
529 fn emit_span_lint<S: Into<MultiSpan>>(
530 &self,
531 lint: &'static Lint,
532 span: S,
533 decorator: impl for<'a> Diagnostic<'a, ()>,
534 ) {
535 self.opt_span_diag_lint(lint, Some(span), decorator);
536 }
537
538 fn emit_diag_lint(&self, lint: &'static Lint, decorator: impl for<'a> Diagnostic<'a, ()>) {
541 self.opt_span_diag_lint(lint, None as Option<Span>, decorator);
542 }
543
544 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource;
546
547 fn fulfill_expectation(&self, expectation: LintExpectationId) {
555 self.sess()
560 .dcx()
561 .struct_expect(
562 "this is a dummy diagnostic, to submit and store an expectation",
563 expectation,
564 )
565 .emit();
566 }
567}
568
569impl<'a> EarlyContext<'a> {
570 pub(crate) fn new(
571 sess: &'a Session,
572 features: &'a Features,
573 lint_added_lints: bool,
574 lint_store: &'a LintStore,
575 registered_tools: &'a RegisteredTools,
576 buffered: LintBuffer,
577 ) -> EarlyContext<'a> {
578 EarlyContext {
579 builder: LintLevelsBuilder::new(
580 sess,
581 features,
582 lint_added_lints,
583 lint_store,
584 registered_tools,
585 ),
586 buffered,
587 }
588 }
589}
590
591impl<'tcx> LintContext for LateContext<'tcx> {
592 fn sess(&self) -> &Session {
594 self.tcx.sess
595 }
596
597 fn opt_span_diag_lint<S: Into<MultiSpan>>(
598 &self,
599 lint: &'static Lint,
600 span: Option<S>,
601 decorate: impl for<'a> Diagnostic<'a, ()>,
602 ) {
603 let hir_id = self.last_node_with_lint_attrs;
604
605 match span {
606 Some(s) => self.tcx.emit_node_span_lint(lint, hir_id, s, decorate),
607 None => self.tcx.emit_node_lint(lint, hir_id, decorate),
608 }
609 }
610
611 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
612 self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs)
613 }
614}
615
616impl LintContext for EarlyContext<'_> {
617 fn sess(&self) -> &Session {
619 self.builder.sess()
620 }
621
622 fn opt_span_diag_lint<S: Into<MultiSpan>>(
623 &self,
624 lint: &'static Lint,
625 span: Option<S>,
626 decorator: impl for<'a> Diagnostic<'a, ()>,
627 ) {
628 self.builder.opt_span_diag_lint(lint, span.map(|s| s.into()), decorator)
629 }
630
631 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
632 self.builder.lint_level(lint)
633 }
634}
635
636impl<'tcx> LateContext<'tcx> {
637 pub fn typing_mode(&self) -> TypingMode<'tcx> {
640 TypingMode::non_body_analysis()
643 }
644
645 pub fn typing_env(&self) -> TypingEnv<'tcx> {
646 TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
647 }
648
649 pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
650 self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
651 }
652
653 pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
654 self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
655 }
656
657 pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
660 self.cached_typeck_results.get().or_else(|| {
661 self.enclosing_body.map(|body| {
662 let typeck_results = self.tcx.typeck_body(body);
663 self.cached_typeck_results.set(Some(typeck_results));
664 typeck_results
665 })
666 })
667 }
668
669 #[track_caller]
673 pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
674 self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body")
675 }
676
677 pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
681 match *qpath {
682 hir::QPath::Resolved(_, path) => path.res,
683 hir::QPath::TypeRelative(..) => self
684 .maybe_typeck_results()
685 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
686 .or_else(|| {
687 self.tcx
688 .has_typeck_results(id.owner.def_id)
689 .then(|| self.tcx.typeck(id.owner.def_id))
690 })
691 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
692 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
693 }
694 }
695
696 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
716 struct LintPathPrinter<'tcx> {
717 tcx: TyCtxt<'tcx>,
718 path: Vec<Symbol>,
719 }
720
721 impl<'tcx> Printer<'tcx> for LintPathPrinter<'tcx> {
722 fn tcx(&self) -> TyCtxt<'tcx> {
723 self.tcx
724 }
725
726 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
727 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
729
730 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
731 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
733
734 fn print_dyn_existential(
735 &mut self,
736 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
737 ) -> Result<(), PrintError> {
738 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
740
741 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
742 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
744
745 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
746 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)];
747 Ok(())
748 }
749
750 fn print_path_with_qualified(
751 &mut self,
752 self_ty: Ty<'tcx>,
753 trait_ref: Option<ty::TraitRef<'tcx>>,
754 ) -> Result<(), PrintError> {
755 if trait_ref.is_none()
756 && let ty::Adt(def, args) = self_ty.kind()
757 {
758 return self.print_def_path(def.did(), args);
759 }
760
761 {
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!({
763 self.path = vec![match trait_ref {
764 Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
765 None => Symbol::intern(&format!("<{self_ty}>")),
766 }];
767 Ok(())
768 })
769 }
770
771 fn print_path_with_impl(
772 &mut self,
773 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
774 self_ty: Ty<'tcx>,
775 trait_ref: Option<ty::TraitRef<'tcx>>,
776 ) -> Result<(), PrintError> {
777 print_prefix(self)?;
778
779 self.path.push(match trait_ref {
781 Some(trait_ref) => {
782 {
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!(
783 "<impl {} for {}>",
784 trait_ref.print_only_trait_path(),
785 self_ty
786 )))
787 }
788 None => {
789 {
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}>")))
790 }
791 });
792
793 Ok(())
794 }
795
796 fn print_path_with_simple(
797 &mut self,
798 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
799 disambiguated_data: &DisambiguatedDefPathData,
800 ) -> Result<(), PrintError> {
801 print_prefix(self)?;
802
803 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
805 return Ok(());
806 }
807
808 self.path.push(match disambiguated_data.data.get_opt_name() {
809 Some(sym) => sym,
810 None => Symbol::intern(&disambiguated_data.data.to_string()),
811 });
812 Ok(())
813 }
814
815 fn print_path_with_generic_args(
816 &mut self,
817 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
818 _args: &[GenericArg<'tcx>],
819 ) -> Result<(), PrintError> {
820 print_prefix(self)
821 }
822 }
823
824 let mut p = LintPathPrinter { tcx: self.tcx, path: ::alloc::vec::Vec::new()vec![] };
825 p.print_def_path(def_id, &[]).unwrap();
826 p.path
827 }
828
829 pub fn get_associated_type(
832 &self,
833 self_ty: Ty<'tcx>,
834 trait_id: DefId,
835 name: Symbol,
836 ) -> Option<Ty<'tcx>> {
837 let tcx = self.tcx;
838 tcx.associated_items(trait_id)
839 .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
840 .and_then(|assoc| {
841 let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
842 tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()
843 })
844 }
845
846 pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
850 let has_attr = |id: hir::HirId| -> bool {
851 for attr in self.tcx.hir_attrs(id) {
852 if attr.span().desugaring_kind().is_none() {
853 return true;
854 }
855 }
856 false
857 };
858 expr.precedence(&has_attr)
859 }
860
861 pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
877 expr = expr.peel_blocks();
878
879 while let hir::ExprKind::Path(ref qpath) = expr.kind
880 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
881 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
882 _ => None,
883 }
884 && let Some(init) = match parent_node {
885 hir::Node::Expr(expr) => Some(expr),
886 hir::Node::LetStmt(hir::LetStmt {
887 init,
888 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
890 ..
891 }) => *init,
892 _ => None,
893 }
894 {
895 expr = init.peel_blocks();
896 }
897 expr
898 }
899
900 pub fn expr_or_init_with_outside_body<'a>(
923 &self,
924 mut expr: &'a hir::Expr<'tcx>,
925 ) -> &'a hir::Expr<'tcx> {
926 expr = expr.peel_blocks();
927
928 while let hir::ExprKind::Path(ref qpath) = expr.kind
929 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
930 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
931 Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
932 _ => None,
933 }
934 && let Some(init) = match parent_node {
935 hir::Node::Expr(expr) => Some(expr),
936 hir::Node::LetStmt(hir::LetStmt {
937 init,
938 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
940 ..
941 }) => *init,
942 hir::Node::Item(item) => match item.kind {
943 hir::ItemKind::Const(.., hir::ConstItemRhs::Body(body_id))
945 | hir::ItemKind::Static(.., body_id) => Some(self.tcx.hir_body(body_id).value),
946 _ => None,
947 },
948 _ => None,
949 }
950 {
951 expr = init.peel_blocks();
952 }
953 expr
954 }
955}
956
957impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
958 #[inline]
959 fn data_layout(&self) -> &abi::TargetDataLayout {
960 &self.tcx.data_layout
961 }
962}
963
964impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
965 #[inline]
966 fn tcx(&self) -> TyCtxt<'tcx> {
967 self.tcx
968 }
969}
970
971impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
972 #[inline]
973 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
974 self.typing_env()
975 }
976}
977
978impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
979 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
980
981 #[inline]
982 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
983 err
984 }
985}