1use std::slice;
7
8use rustc_abi as abi;
9use rustc_ast::BindingMode;
10use rustc_ast::util::parser::ExprPrecedence;
11use rustc_data_structures::fx::FxIndexMap;
12use rustc_data_structures::sync;
13use rustc_data_structures::unord::UnordMap;
14use rustc_errors::{Diagnostic, LintBuffer, MultiSpan};
15use rustc_feature::Features;
16use rustc_hir as hir;
17use rustc_hir::def::Res;
18use rustc_hir::def_id::{CrateNum, DefId};
19use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
20use rustc_hir::{Pat, PatKind};
21use rustc_middle::bug;
22use rustc_middle::lint::{LevelSpec, StableLevelSpec, UnstableLevelSpec};
23use rustc_middle::middle::privacy::EffectiveVisibilities;
24use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
25use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
26use rustc_middle::ty::{
27 self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode, Unnormalized,
28};
29use rustc_session::lint::{
30 FutureIncompatibleInfo, Lint, LintExpectationId, LintId, StableLintExpectationId,
31 UnstableLintExpectationId,
32};
33use rustc_session::{DynLintStore, Session};
34use rustc_span::edit_distance::find_best_match_for_names;
35use rustc_span::{Ident, Span, Symbol, sym};
36use tracing::debug;
37
38use self::TargetLint::*;
39use crate::levels::LintLevelsBuilder;
40use crate::passes::{EarlyLintPassObject, LateLintPassObject};
41
42pub(crate) type EarlyLintPassFactory =
43 Box<dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync>;
44type LateLintPassFactory =
45 Box<dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync>;
46
47pub struct LintStore {
54 lints: Vec<&'static Lint>,
56
57 pub(crate) pre_expansion_lint_passes: Vec<EarlyLintPassFactory>,
64
65 pub(crate) early_lint_passes: Vec<EarlyLintPassFactory>,
67
68 pub(crate) late_lint_passes: Vec<LateLintPassFactory>,
77
78 pub(crate) late_lint_mod_passes: Vec<LateLintPassFactory>,
81
82 by_name: UnordMap<String, TargetLint>,
84
85 lint_groups: FxIndexMap<&'static str, LintGroup>,
87}
88
89impl DynLintStore for LintStore {
90 fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = rustc_session::LintGroup> + '_> {
91 Box::new(self.get_lint_groups().map(|(name, lints, is_externally_loaded)| {
92 rustc_session::LintGroup { name, lints, is_externally_loaded }
93 }))
94 }
95}
96
97#[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)]
99enum TargetLint {
100 Id(LintId),
102
103 Renamed(String, LintId),
105
106 Removed(String),
109
110 Ignored,
115}
116
117struct LintAlias {
118 name: &'static str,
119 silent: bool,
121}
122
123struct LintGroup {
124 lint_ids: Vec<LintId>,
125 is_externally_loaded: bool,
126 depr: Option<LintAlias>,
127}
128
129#[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)]
130pub enum CheckLintNameResult<'a> {
131 Ok(&'a [LintId]),
132 NoLint(Option<(Symbol, bool)>),
134 NoTool,
136 Renamed(String),
138 Removed(String),
140
141 Tool(&'a [LintId], Option<String>),
145
146 MissingTool,
150}
151
152impl LintStore {
153 pub fn new() -> LintStore {
154 LintStore {
155 lints: ::alloc::vec::Vec::new()vec![],
156 pre_expansion_lint_passes: ::alloc::vec::Vec::new()vec![],
157 early_lint_passes: ::alloc::vec::Vec::new()vec![],
158 late_lint_passes: ::alloc::vec::Vec::new()vec![],
159 late_lint_mod_passes: ::alloc::vec::Vec::new()vec![],
160 by_name: Default::default(),
161 lint_groups: Default::default(),
162 }
163 }
164
165 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
166 &self.lints
167 }
168
169 pub fn get_lint_groups(&self) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> {
170 self.lint_groups
171 .iter()
172 .filter(|(_, LintGroup { depr, .. })| {
173 depr.is_none()
175 })
176 .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
177 (*k, lint_ids.clone(), *is_externally_loaded)
178 })
179 }
180
181 pub fn get_all_group_names(&self) -> impl Iterator<Item = &'static str> {
183 self.lint_groups.keys().copied()
184 }
185
186 pub fn register_pre_expansion_lint_pass(&mut self, pass: EarlyLintPassFactory) {
188 self.pre_expansion_lint_passes.push(pass);
189 }
190
191 pub fn register_early_lint_pass(&mut self, pass: EarlyLintPassFactory) {
193 self.early_lint_passes.push(pass);
194 }
195
196 pub fn register_late_lint_pass(&mut self, pass: LateLintPassFactory) {
198 self.late_lint_passes.push(pass);
199 }
200
201 pub fn register_late_lint_mod_pass(&mut self, pass: LateLintPassFactory) {
203 self.late_lint_mod_passes.push(pass);
204 }
205
206 pub fn register_lints(&mut self, lints: &[&'static Lint]) {
208 for lint in lints {
209 self.lints.push(lint);
210
211 let id = LintId::of(lint);
212 if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
213 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
lint.name_lower()))bug!("duplicate specification of lint {}", lint.name_lower())
214 }
215
216 if let Some(FutureIncompatibleInfo { reason, .. }) = lint.future_incompatible {
217 if let Some(edition) = reason.edition() {
218 self.lint_groups
219 .entry(edition.lint_name())
220 .or_insert(LintGroup {
221 lint_ids: ::alloc::vec::Vec::new()vec![],
222 is_externally_loaded: lint.is_externally_loaded,
223 depr: None,
224 })
225 .lint_ids
226 .push(id);
227 } else {
228 self.lint_groups
232 .entry("future_incompatible")
233 .or_insert(LintGroup {
234 lint_ids: ::alloc::vec::Vec::new()vec![],
235 is_externally_loaded: lint.is_externally_loaded,
236 depr: None,
237 })
238 .lint_ids
239 .push(id);
240 }
241 }
242 }
243 }
244
245 fn insert_group(&mut self, name: &'static str, group: LintGroup) {
246 let previous = self.lint_groups.insert(name, group);
247 if previous.is_some() {
248 ::rustc_middle::util::bug::bug_fmt(format_args!("group {0:?} already exists",
name));bug!("group {name:?} already exists");
249 }
250 }
251
252 pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) {
253 let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else {
254 ::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:?}")
255 };
256
257 self.insert_group(
258 alias,
259 LintGroup {
260 lint_ids: lint_ids.clone(),
261 is_externally_loaded: false,
262 depr: Some(LintAlias { name: group_name, silent: true }),
263 },
264 );
265 }
266
267 pub fn register_group(
268 &mut self,
269 is_externally_loaded: bool,
270 name: &'static str,
271 deprecated_name: Option<&'static str>,
272 to: Vec<LintId>,
273 ) {
274 if let Some(deprecated) = deprecated_name {
275 self.insert_group(
276 deprecated,
277 LintGroup {
278 lint_ids: to.clone(),
279 is_externally_loaded,
280 depr: Some(LintAlias { name, silent: false }),
281 },
282 );
283 }
284 self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None });
285 }
286
287 #[track_caller]
291 pub fn register_ignored(&mut self, name: &str) {
292 if self.by_name.insert(name.to_string(), Ignored).is_some() {
293 ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
name));bug!("duplicate specification of lint {}", name);
294 }
295 }
296
297 #[track_caller]
299 pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
300 let Some(&Id(target)) = self.by_name.get(new_name) else {
301 ::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);
302 };
303 self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
304 }
305
306 pub fn register_removed(&mut self, name: &str, reason: &str) {
307 self.by_name.insert(name.into(), Removed(reason.into()));
308 }
309
310 pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
311 match self.by_name.get(lint_name) {
312 Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
313 Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)),
314 Some(Removed(_)) => None,
315 Some(Ignored) => Some(&[]),
316 None => match self.lint_groups.get(lint_name) {
317 Some(LintGroup { lint_ids, .. }) => Some(lint_ids),
318 None => None,
319 },
320 }
321 }
322
323 pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
325 {
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:325",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(325u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::context"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("is_lint_group(lint_name={0:?}, lint_groups={1:?})",
lint_name, self.lint_groups.keys().collect::<Vec<_>>()) as
&dyn ::tracing::field::Value))])
});
} else { ; }
};debug!(
326 "is_lint_group(lint_name={:?}, lint_groups={:?})",
327 lint_name,
328 self.lint_groups.keys().collect::<Vec<_>>()
329 );
330 let lint_name_str = lint_name.as_str();
331 self.lint_groups.contains_key(lint_name_str) || {
332 let warnings_name_str = crate::WARNINGS.name_lower();
333 lint_name_str == warnings_name_str
334 }
335 }
336
337 pub fn check_lint_name(
345 &self,
346 lint_name: &str,
347 tool_name: Option<Symbol>,
348 registered_lint_tools: &RegisteredTools,
349 ) -> CheckLintNameResult<'_> {
350 if let Some(tool_name) = tool_name {
351 if tool_name != sym::rustc
353 && tool_name != sym::rustdoc
354 && !registered_lint_tools.contains(&Ident::with_dummy_span(tool_name))
355 {
356 return CheckLintNameResult::NoTool;
357 }
358 }
359
360 let complete_name = if let Some(tool_name) = tool_name {
361 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}")
362 } else {
363 lint_name.to_string()
364 };
365 if let Some(tool_name) = tool_name {
367 match self.by_name.get(&complete_name) {
368 None => match self.lint_groups.get(&*complete_name) {
369 None => {
371 {
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:373",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(373u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::context"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("lints={0:?}",
self.by_name) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("lints={:?}", self.by_name);
374 let tool_prefix = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::", tool_name))
})format!("{tool_name}::");
375
376 return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
377 self.no_lint_suggestion(&complete_name, tool_name.as_str())
378 } else {
379 CheckLintNameResult::MissingTool
382 };
383 }
384 Some(LintGroup { lint_ids, depr, .. }) => {
385 return if let &Some(LintAlias { name, silent: false }) = depr {
386 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
387 } else {
388 CheckLintNameResult::Tool(lint_ids, None)
389 };
390 }
391 },
392 Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
393 _ => {}
396 }
397 }
398 match self.by_name.get(&complete_name) {
399 Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
400 Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
401 None => match self.lint_groups.get(&*complete_name) {
402 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
405 Some(LintGroup { lint_ids, depr, .. }) => {
406 if let &Some(LintAlias { name, silent: false }) = depr {
408 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
409 } else {
410 CheckLintNameResult::Ok(lint_ids)
411 }
412 }
413 },
414 Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
415 Some(&Ignored) => CheckLintNameResult::Ok(&[]),
416 }
417 }
418
419 fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
420 let name_lower = lint_name.to_lowercase();
421
422 if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() {
423 return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
425 }
426
427 #[allow(rustc::potential_query_instability)]
433 let mut groups: Vec<_> = self
434 .lint_groups
435 .iter()
436 .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k))
437 .collect();
438 groups.sort();
439 let groups = groups.iter().map(|k| Symbol::intern(k));
440 let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
441 let names: Vec<Symbol> = groups.chain(lints).collect();
442 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)];
443 if let Some(stripped) = name_lower.split("::").last() {
444 lookups.push(Symbol::intern(stripped));
445 }
446 let res = find_best_match_for_names(&names, &lookups, None);
447 let is_rustc = res.map_or_else(
448 || false,
449 |s| name_lower.contains("::") && !s.as_str().starts_with(tool_name),
450 );
451 let suggestion = res.map(|s| (s, is_rustc));
452 CheckLintNameResult::NoLint(suggestion)
453 }
454
455 fn check_tool_name_for_backwards_compat(
456 &self,
457 lint_name: &str,
458 tool_name: &str,
459 ) -> CheckLintNameResult<'_> {
460 let complete_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
})format!("{tool_name}::{lint_name}");
461 match self.by_name.get(&complete_name) {
462 None => match self.lint_groups.get(&*complete_name) {
463 None => self.no_lint_suggestion(lint_name, tool_name),
465 Some(LintGroup { lint_ids, .. }) => {
466 CheckLintNameResult::Tool(lint_ids, Some(complete_name))
467 }
468 },
469 Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)),
470 Some(other) => {
471 {
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:471",
"rustc_lint::context", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
::tracing_core::__macro_support::Option::Some(471u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::context"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("got renamed lint {0:?}",
other) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("got renamed lint {:?}", other);
472 CheckLintNameResult::NoLint(None)
473 }
474 }
475 }
476}
477
478pub struct LateContext<'tcx> {
480 pub tcx: TyCtxt<'tcx>,
482
483 pub enclosing_body: Option<hir::BodyId>,
485
486 pub typeck_results: 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 type LintExpectationId: Copy + Into<LintExpectationId>;
512
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_spec(&self, lint: &'static Lint) -> LevelSpec<Self::LintExpectationId>;
542
543 fn fulfill_expectation(&self, expectation: Self::LintExpectationId) {
551 self.sess()
556 .dcx()
557 .struct_expect(
558 "this is a dummy diagnostic, to submit and store an expectation",
559 expectation.into(),
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_lint_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_lint_tools,
581 ),
582 buffered,
583 }
584 }
585}
586
587impl<'tcx> LintContext for LateContext<'tcx> {
588 type LintExpectationId = StableLintExpectationId;
589
590 fn sess(&self) -> &Session {
592 self.tcx.sess
593 }
594
595 fn opt_span_lint<S: Into<MultiSpan>>(
596 &self,
597 lint: &'static Lint,
598 span: Option<S>,
599 decorate: impl for<'a> Diagnostic<'a, ()>,
600 ) {
601 let hir_id = self.last_node_with_lint_attrs;
602
603 match span {
604 Some(s) => self.tcx.emit_node_span_lint(lint, hir_id, s, decorate),
605 None => self.tcx.emit_node_lint(lint, hir_id, decorate),
606 }
607 }
608
609 fn get_lint_level_spec(&self, lint: &'static Lint) -> StableLevelSpec {
610 self.tcx.lint_level_spec_at_node(lint, self.last_node_with_lint_attrs)
611 }
612}
613
614impl LintContext for EarlyContext<'_> {
615 type LintExpectationId = UnstableLintExpectationId;
616
617 fn sess(&self) -> &Session {
619 self.builder.sess()
620 }
621
622 fn opt_span_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_lint(lint, span.map(|s| s.into()), decorator)
629 }
630
631 fn get_lint_level_spec(&self, lint: &'static Lint) -> UnstableLevelSpec {
632 self.builder.lint_level_spec(lint)
633 }
634}
635
636impl<'tcx> LateContext<'tcx> {
637 pub fn typing_mode(&self) -> TypingMode<'tcx> {
640 if let Some(body_id) = self.enclosing_body
641 && self.tcx.use_typing_mode_post_typeck_until_borrowck()
642 {
643 let def_id = self.tcx.hir_enclosing_body_owner(body_id.hir_id);
644 TypingMode::post_borrowck_analysis(self.tcx, def_id)
645 } else {
646 TypingMode::non_body_analysis()
647 }
648 }
649
650 pub fn typing_env(&self) -> TypingEnv<'tcx> {
651 TypingEnv::new(self.param_env, self.typing_mode())
652 }
653
654 pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
655 self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
656 }
657
658 pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
659 self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
660 }
661
662 #[inline]
666 #[track_caller]
667 pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
668 self.typeck_results.expect("`LateContext::typeck_results` called outside of body")
669 }
670
671 pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
675 match *qpath {
676 hir::QPath::Resolved(_, path) => path.res,
677 hir::QPath::TypeRelative(..) => self
678 .typeck_results
679 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
680 .or_else(|| {
681 self.tcx
682 .has_typeck_results(id.owner.def_id)
683 .then(|| self.tcx.typeck(id.owner.def_id))
684 })
685 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
686 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
687 }
688 }
689
690 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
710 struct LintPathPrinter<'tcx> {
711 tcx: TyCtxt<'tcx>,
712 path: Vec<Symbol>,
713 }
714
715 impl<'tcx> Printer<'tcx> for LintPathPrinter<'tcx> {
716 fn tcx(&self) -> TyCtxt<'tcx> {
717 self.tcx
718 }
719
720 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
721 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
723
724 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
725 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
727
728 fn print_dyn_existential(
729 &mut self,
730 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
731 ) -> Result<(), PrintError> {
732 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
734
735 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
736 ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); }
738
739 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
740 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)];
741 Ok(())
742 }
743
744 fn print_path_with_qualified(
745 &mut self,
746 self_ty: Ty<'tcx>,
747 trait_ref: Option<ty::TraitRef<'tcx>>,
748 ) -> Result<(), PrintError> {
749 if trait_ref.is_none()
750 && let ty::Adt(def, args) = self_ty.kind()
751 {
752 return self.print_def_path(def.did(), args);
753 }
754
755 {
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!({
757 self.path = vec![match trait_ref {
758 Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
759 None => Symbol::intern(&format!("<{self_ty}>")),
760 }];
761 Ok(())
762 })
763 }
764
765 fn print_path_with_impl(
766 &mut self,
767 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
768 self_ty: Ty<'tcx>,
769 trait_ref: Option<ty::TraitRef<'tcx>>,
770 ) -> Result<(), PrintError> {
771 print_prefix(self)?;
772
773 self.path.push(match trait_ref {
775 Some(trait_ref) => {
776 {
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!(
777 "<impl {} for {}>",
778 trait_ref.print_only_trait_path(),
779 self_ty
780 )))
781 }
782 None => {
783 {
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}>")))
784 }
785 });
786
787 Ok(())
788 }
789
790 fn print_path_with_simple(
791 &mut self,
792 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
793 disambiguated_data: &DisambiguatedDefPathData,
794 ) -> Result<(), PrintError> {
795 print_prefix(self)?;
796
797 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
799 return Ok(());
800 }
801
802 self.path.push(match disambiguated_data.data.get_opt_name() {
803 Some(sym) => sym,
804 None => Symbol::intern(&disambiguated_data.data.to_string()),
805 });
806 Ok(())
807 }
808
809 fn print_path_with_generic_args(
810 &mut self,
811 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
812 _args: &[GenericArg<'tcx>],
813 ) -> Result<(), PrintError> {
814 print_prefix(self)
815 }
816 }
817
818 let mut p = LintPathPrinter { tcx: self.tcx, path: ::alloc::vec::Vec::new()vec![] };
819 p.print_def_path(def_id, &[]).unwrap();
820 p.path
821 }
822
823 pub fn get_associated_type(
826 &self,
827 self_ty: Ty<'tcx>,
828 trait_id: DefId,
829 name: Symbol,
830 ) -> Option<Ty<'tcx>> {
831 let tcx = self.tcx;
832 tcx.associated_items(trait_id)
833 .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
834 .and_then(|assoc| {
835 let proj = Ty::new_projection(tcx, ty::IsRigid::No, assoc.def_id, [self_ty]);
836 tcx.try_normalize_erasing_regions(self.typing_env(), Unnormalized::new_wip(proj))
837 .ok()
838 })
839 }
840
841 pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
845 let has_attr = |id: hir::HirId| -> bool {
846 self.tcx.hir_attrs(id).iter().any(hir::Attribute::is_prefix_attr_for_suggestions)
847 };
848 expr.precedence(&has_attr)
849 }
850
851 pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
867 expr = expr.peel_blocks();
868
869 while let hir::ExprKind::Path(ref qpath) = expr.kind
870 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
871 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
872 _ => None,
873 }
874 && let Some(init) = match parent_node {
875 hir::Node::Expr(expr) => Some(expr),
876 hir::Node::LetStmt(hir::LetStmt {
877 init,
878 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
880 ..
881 }) => *init,
882 _ => None,
883 }
884 {
885 expr = init.peel_blocks();
886 }
887 expr
888 }
889
890 pub fn expr_or_init_with_outside_body<'a>(
913 &self,
914 mut expr: &'a hir::Expr<'tcx>,
915 ) -> &'a hir::Expr<'tcx> {
916 expr = expr.peel_blocks();
917
918 while let hir::ExprKind::Path(ref qpath) = expr.kind
919 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
920 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
921 Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
922 _ => None,
923 }
924 && let Some(init) = match parent_node {
925 hir::Node::Expr(expr) => Some(expr),
926 hir::Node::LetStmt(hir::LetStmt {
927 init,
928 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
930 ..
931 }) => *init,
932 hir::Node::Item(item) => match item.kind {
933 hir::ItemKind::Const(.., hir::ConstItemRhs::Body(body_id))
935 | hir::ItemKind::Static(.., body_id) => Some(self.tcx.hir_body(body_id).value),
936 _ => None,
937 },
938 _ => None,
939 }
940 {
941 expr = init.peel_blocks();
942 }
943 expr
944 }
945}
946
947impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
948 #[inline]
949 fn data_layout(&self) -> &abi::TargetDataLayout {
950 &self.tcx.data_layout
951 }
952}
953
954impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
955 #[inline]
956 fn tcx(&self) -> TyCtxt<'tcx> {
957 self.tcx
958 }
959}
960
961impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
962 #[inline]
963 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
964 self.typing_env()
965 }
966}
967
968impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
969 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
970
971 #[inline]
972 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
973 err
974 }
975}