1use std::cell::Cell;
7use std::slice;
8
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::{Diag, LintBuffer, LintDiagnostic, MultiSpan};
15use rustc_feature::Features;
16use rustc_hir::def::Res;
17use rustc_hir::def_id::{CrateNum, DefId};
18use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
19use rustc_hir::{Pat, PatKind};
20use rustc_middle::bug;
21use rustc_middle::lint::LevelAndSource;
22use rustc_middle::middle::privacy::EffectiveVisibilities;
23use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
24use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
25use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode};
26use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintExpectationId, LintId};
27use rustc_session::{DynLintStore, Session};
28use rustc_span::edit_distance::find_best_match_for_names;
29use rustc_span::{Ident, Span, Symbol, sym};
30use tracing::debug;
31use {rustc_abi as abi, rustc_hir as hir};
32
33use self::TargetLint::*;
34use crate::levels::LintLevelsBuilder;
35use crate::passes::{EarlyLintPassObject, LateLintPassObject};
36
37type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync;
38type LateLintPassFactory =
39 dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
40
41pub struct LintStore {
43 lints: Vec<&'static Lint>,
45
46 pub pre_expansion_passes: Vec<Box<EarlyLintPassFactory>>,
53 pub early_passes: Vec<Box<EarlyLintPassFactory>>,
54 pub late_passes: Vec<Box<LateLintPassFactory>>,
55 pub late_module_passes: Vec<Box<LateLintPassFactory>>,
57
58 by_name: UnordMap<String, TargetLint>,
60
61 lint_groups: FxIndexMap<&'static str, LintGroup>,
63}
64
65impl DynLintStore for LintStore {
66 fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = rustc_session::LintGroup> + '_> {
67 Box::new(self.get_lint_groups().map(|(name, lints, is_externally_loaded)| {
68 rustc_session::LintGroup { name, lints, is_externally_loaded }
69 }))
70 }
71}
72
73#[derive(Debug)]
75enum TargetLint {
76 Id(LintId),
78
79 Renamed(String, LintId),
81
82 Removed(String),
85
86 Ignored,
91}
92
93struct LintAlias {
94 name: &'static str,
95 silent: bool,
97}
98
99struct LintGroup {
100 lint_ids: Vec<LintId>,
101 is_externally_loaded: bool,
102 depr: Option<LintAlias>,
103}
104
105#[derive(Debug)]
106pub enum CheckLintNameResult<'a> {
107 Ok(&'a [LintId]),
108 NoLint(Option<(Symbol, bool)>),
110 NoTool,
112 Renamed(String),
114 Removed(String),
116
117 Tool(&'a [LintId], Option<String>),
121
122 MissingTool,
126}
127
128impl LintStore {
129 pub fn new() -> LintStore {
130 LintStore {
131 lints: vec![],
132 pre_expansion_passes: vec![],
133 early_passes: vec![],
134 late_passes: vec![],
135 late_module_passes: vec![],
136 by_name: Default::default(),
137 lint_groups: Default::default(),
138 }
139 }
140
141 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
142 &self.lints
143 }
144
145 pub fn get_lint_groups(&self) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> {
146 self.lint_groups
147 .iter()
148 .filter(|(_, LintGroup { depr, .. })| {
149 depr.is_none()
151 })
152 .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
153 (*k, lint_ids.clone(), *is_externally_loaded)
154 })
155 }
156
157 pub fn register_early_pass(
158 &mut self,
159 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
160 ) {
161 self.early_passes.push(Box::new(pass));
162 }
163
164 pub fn register_pre_expansion_pass(
171 &mut self,
172 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
173 ) {
174 self.pre_expansion_passes.push(Box::new(pass));
175 }
176
177 pub fn register_late_pass(
178 &mut self,
179 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
180 + 'static
181 + sync::DynSend
182 + sync::DynSync,
183 ) {
184 self.late_passes.push(Box::new(pass));
185 }
186
187 pub fn register_late_mod_pass(
188 &mut self,
189 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
190 + 'static
191 + sync::DynSend
192 + sync::DynSync,
193 ) {
194 self.late_module_passes.push(Box::new(pass));
195 }
196
197 pub fn register_lints(&mut self, lints: &[&'static Lint]) {
199 for lint in lints {
200 self.lints.push(lint);
201
202 let id = LintId::of(lint);
203 if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
204 bug!("duplicate specification of lint {}", lint.name_lower())
205 }
206
207 if let Some(FutureIncompatibleInfo { reason, .. }) = lint.future_incompatible {
208 if let Some(edition) = reason.edition() {
209 self.lint_groups
210 .entry(edition.lint_name())
211 .or_insert(LintGroup {
212 lint_ids: vec![],
213 is_externally_loaded: lint.is_externally_loaded,
214 depr: None,
215 })
216 .lint_ids
217 .push(id);
218 } else {
219 self.lint_groups
223 .entry("future_incompatible")
224 .or_insert(LintGroup {
225 lint_ids: vec![],
226 is_externally_loaded: lint.is_externally_loaded,
227 depr: None,
228 })
229 .lint_ids
230 .push(id);
231 }
232 }
233 }
234 }
235
236 fn insert_group(&mut self, name: &'static str, group: LintGroup) {
237 let previous = self.lint_groups.insert(name, group);
238 if previous.is_some() {
239 bug!("group {name:?} already exists");
240 }
241 }
242
243 pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) {
244 let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else {
245 bug!("group alias {alias:?} points to unregistered group {group_name:?}")
246 };
247
248 self.insert_group(
249 alias,
250 LintGroup {
251 lint_ids: lint_ids.clone(),
252 is_externally_loaded: false,
253 depr: Some(LintAlias { name: group_name, silent: true }),
254 },
255 );
256 }
257
258 pub fn register_group(
259 &mut self,
260 is_externally_loaded: bool,
261 name: &'static str,
262 deprecated_name: Option<&'static str>,
263 to: Vec<LintId>,
264 ) {
265 if let Some(deprecated) = deprecated_name {
266 self.insert_group(
267 deprecated,
268 LintGroup {
269 lint_ids: to.clone(),
270 is_externally_loaded,
271 depr: Some(LintAlias { name, silent: false }),
272 },
273 );
274 }
275 self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None });
276 }
277
278 #[track_caller]
282 pub fn register_ignored(&mut self, name: &str) {
283 if self.by_name.insert(name.to_string(), Ignored).is_some() {
284 bug!("duplicate specification of lint {}", name);
285 }
286 }
287
288 #[track_caller]
290 pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
291 let Some(&Id(target)) = self.by_name.get(new_name) else {
292 bug!("invalid lint renaming of {} to {}", old_name, new_name);
293 };
294 self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
295 }
296
297 pub fn register_removed(&mut self, name: &str, reason: &str) {
298 self.by_name.insert(name.into(), Removed(reason.into()));
299 }
300
301 pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
302 match self.by_name.get(lint_name) {
303 Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
304 Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)),
305 Some(Removed(_)) => None,
306 Some(Ignored) => Some(&[]),
307 None => match self.lint_groups.get(lint_name) {
308 Some(LintGroup { lint_ids, .. }) => Some(lint_ids),
309 None => None,
310 },
311 }
312 }
313
314 pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
316 debug!(
317 "is_lint_group(lint_name={:?}, lint_groups={:?})",
318 lint_name,
319 self.lint_groups.keys().collect::<Vec<_>>()
320 );
321 let lint_name_str = lint_name.as_str();
322 self.lint_groups.contains_key(lint_name_str) || {
323 let warnings_name_str = crate::WARNINGS.name_lower();
324 lint_name_str == warnings_name_str
325 }
326 }
327
328 pub fn check_lint_name(
336 &self,
337 lint_name: &str,
338 tool_name: Option<Symbol>,
339 registered_tools: &RegisteredTools,
340 ) -> CheckLintNameResult<'_> {
341 if let Some(tool_name) = tool_name {
342 if tool_name != sym::rustc
344 && tool_name != sym::rustdoc
345 && !registered_tools.contains(&Ident::with_dummy_span(tool_name))
346 {
347 return CheckLintNameResult::NoTool;
348 }
349 }
350
351 let complete_name = if let Some(tool_name) = tool_name {
352 format!("{tool_name}::{lint_name}")
353 } else {
354 lint_name.to_string()
355 };
356 if let Some(tool_name) = tool_name {
358 match self.by_name.get(&complete_name) {
359 None => match self.lint_groups.get(&*complete_name) {
360 None => {
362 debug!("lints={:?}", self.by_name);
365 let tool_prefix = format!("{tool_name}::");
366
367 return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
368 self.no_lint_suggestion(&complete_name, tool_name.as_str())
369 } else {
370 CheckLintNameResult::MissingTool
373 };
374 }
375 Some(LintGroup { lint_ids, depr, .. }) => {
376 return if let &Some(LintAlias { name, silent: false }) = depr {
377 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
378 } else {
379 CheckLintNameResult::Tool(lint_ids, None)
380 };
381 }
382 },
383 Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
384 _ => {}
387 }
388 }
389 match self.by_name.get(&complete_name) {
390 Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
391 Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
392 None => match self.lint_groups.get(&*complete_name) {
393 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
396 Some(LintGroup { lint_ids, depr, .. }) => {
397 if let &Some(LintAlias { name, silent: false }) = depr {
399 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
400 } else {
401 CheckLintNameResult::Ok(lint_ids)
402 }
403 }
404 },
405 Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
406 Some(&Ignored) => CheckLintNameResult::Ok(&[]),
407 }
408 }
409
410 fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
411 let name_lower = lint_name.to_lowercase();
412
413 if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() {
414 return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
416 }
417
418 #[allow(rustc::potential_query_instability)]
424 let mut groups: Vec<_> = self
425 .lint_groups
426 .iter()
427 .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k))
428 .collect();
429 groups.sort();
430 let groups = groups.iter().map(|k| Symbol::intern(k));
431 let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
432 let names: Vec<Symbol> = groups.chain(lints).collect();
433 let mut lookups = vec![Symbol::intern(&name_lower)];
434 if let Some(stripped) = name_lower.split("::").last() {
435 lookups.push(Symbol::intern(stripped));
436 }
437 let res = find_best_match_for_names(&names, &lookups, None);
438 let is_rustc = res.map_or_else(
439 || false,
440 |s| name_lower.contains("::") && !s.as_str().starts_with(tool_name),
441 );
442 let suggestion = res.map(|s| (s, is_rustc));
443 CheckLintNameResult::NoLint(suggestion)
444 }
445
446 fn check_tool_name_for_backwards_compat(
447 &self,
448 lint_name: &str,
449 tool_name: &str,
450 ) -> CheckLintNameResult<'_> {
451 let complete_name = format!("{tool_name}::{lint_name}");
452 match self.by_name.get(&complete_name) {
453 None => match self.lint_groups.get(&*complete_name) {
454 None => self.no_lint_suggestion(lint_name, tool_name),
456 Some(LintGroup { lint_ids, .. }) => {
457 CheckLintNameResult::Tool(lint_ids, Some(complete_name))
458 }
459 },
460 Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)),
461 Some(other) => {
462 debug!("got renamed lint {:?}", other);
463 CheckLintNameResult::NoLint(None)
464 }
465 }
466 }
467}
468
469pub struct LateContext<'tcx> {
471 pub tcx: TyCtxt<'tcx>,
473
474 pub enclosing_body: Option<hir::BodyId>,
476
477 pub(super) cached_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
482
483 pub param_env: ty::ParamEnv<'tcx>,
485
486 pub effective_visibilities: &'tcx EffectiveVisibilities,
488
489 pub last_node_with_lint_attrs: hir::HirId,
490
491 pub generics: Option<&'tcx hir::Generics<'tcx>>,
493
494 pub only_module: bool,
496}
497
498pub struct EarlyContext<'a> {
500 pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>,
501 pub buffered: LintBuffer,
502}
503
504pub trait LintContext {
505 fn sess(&self) -> &Session;
506
507 #[rustc_lint_diagnostics]
513 #[track_caller]
514 fn opt_span_lint<S: Into<MultiSpan>>(
515 &self,
516 lint: &'static Lint,
517 span: Option<S>,
518 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
519 );
520
521 fn emit_span_lint<S: Into<MultiSpan>>(
524 &self,
525 lint: &'static Lint,
526 span: S,
527 decorator: impl for<'a> LintDiagnostic<'a, ()>,
528 ) {
529 self.opt_span_lint(lint, Some(span), |lint| {
530 decorator.decorate_lint(lint);
531 });
532 }
533
534 fn emit_span_lint_lazy<S: Into<MultiSpan>, L: for<'a> LintDiagnostic<'a, ()>>(
537 &self,
538 lint: &'static Lint,
539 span: S,
540 decorator: impl FnOnce() -> L,
541 ) {
542 self.opt_span_lint(lint, Some(span), |lint| {
543 let decorator = decorator();
544 decorator.decorate_lint(lint);
545 });
546 }
547
548 #[rustc_lint_diagnostics]
552 #[track_caller]
553 fn span_lint<S: Into<MultiSpan>>(
554 &self,
555 lint: &'static Lint,
556 span: S,
557 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
558 ) {
559 self.opt_span_lint(lint, Some(span), decorate);
560 }
561
562 fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> LintDiagnostic<'a, ()>) {
565 self.opt_span_lint(lint, None as Option<Span>, |lint| {
566 decorator.decorate_lint(lint);
567 });
568 }
569
570 #[rustc_lint_diagnostics]
574 fn lint(&self, lint: &'static Lint, decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>)) {
575 self.opt_span_lint(lint, None as Option<Span>, decorate);
576 }
577
578 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource;
580
581 fn fulfill_expectation(&self, expectation: LintExpectationId) {
589 #[allow(rustc::diagnostic_outside_of_impl)]
594 #[allow(rustc::untranslatable_diagnostic)]
595 self.sess()
596 .dcx()
597 .struct_expect(
598 "this is a dummy diagnostic, to submit and store an expectation",
599 expectation,
600 )
601 .emit();
602 }
603}
604
605impl<'a> EarlyContext<'a> {
606 pub(crate) fn new(
607 sess: &'a Session,
608 features: &'a Features,
609 lint_added_lints: bool,
610 lint_store: &'a LintStore,
611 registered_tools: &'a RegisteredTools,
612 buffered: LintBuffer,
613 ) -> EarlyContext<'a> {
614 EarlyContext {
615 builder: LintLevelsBuilder::new(
616 sess,
617 features,
618 lint_added_lints,
619 lint_store,
620 registered_tools,
621 ),
622 buffered,
623 }
624 }
625}
626
627impl<'tcx> LintContext for LateContext<'tcx> {
628 fn sess(&self) -> &Session {
630 self.tcx.sess
631 }
632
633 #[rustc_lint_diagnostics]
634 fn opt_span_lint<S: Into<MultiSpan>>(
635 &self,
636 lint: &'static Lint,
637 span: Option<S>,
638 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
639 ) {
640 let hir_id = self.last_node_with_lint_attrs;
641
642 match span {
643 Some(s) => self.tcx.node_span_lint(lint, hir_id, s, decorate),
644 None => self.tcx.node_lint(lint, hir_id, decorate),
645 }
646 }
647
648 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
649 self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs)
650 }
651}
652
653impl LintContext for EarlyContext<'_> {
654 fn sess(&self) -> &Session {
656 self.builder.sess()
657 }
658
659 #[rustc_lint_diagnostics]
660 fn opt_span_lint<S: Into<MultiSpan>>(
661 &self,
662 lint: &'static Lint,
663 span: Option<S>,
664 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
665 ) {
666 self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorate)
667 }
668
669 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
670 self.builder.lint_level(lint)
671 }
672}
673
674impl<'tcx> LateContext<'tcx> {
675 pub fn typing_mode(&self) -> TypingMode<'tcx> {
678 TypingMode::non_body_analysis()
681 }
682
683 pub fn typing_env(&self) -> TypingEnv<'tcx> {
684 TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
685 }
686
687 pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
688 self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
689 }
690
691 pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
692 self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
693 }
694
695 pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
698 self.cached_typeck_results.get().or_else(|| {
699 self.enclosing_body.map(|body| {
700 let typeck_results = self.tcx.typeck_body(body);
701 self.cached_typeck_results.set(Some(typeck_results));
702 typeck_results
703 })
704 })
705 }
706
707 #[track_caller]
711 pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
712 self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body")
713 }
714
715 pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
719 match *qpath {
720 hir::QPath::Resolved(_, path) => path.res,
721 hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
722 .maybe_typeck_results()
723 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
724 .or_else(|| {
725 self.tcx
726 .has_typeck_results(id.owner.def_id)
727 .then(|| self.tcx.typeck(id.owner.def_id))
728 })
729 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
730 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
731 }
732 }
733
734 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
754 struct LintPathPrinter<'tcx> {
755 tcx: TyCtxt<'tcx>,
756 path: Vec<Symbol>,
757 }
758
759 impl<'tcx> Printer<'tcx> for LintPathPrinter<'tcx> {
760 fn tcx(&self) -> TyCtxt<'tcx> {
761 self.tcx
762 }
763
764 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
765 unreachable!(); }
767
768 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
769 unreachable!(); }
771
772 fn print_dyn_existential(
773 &mut self,
774 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
775 ) -> Result<(), PrintError> {
776 unreachable!(); }
778
779 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
780 unreachable!(); }
782
783 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
784 self.path = vec![self.tcx.crate_name(cnum)];
785 Ok(())
786 }
787
788 fn print_path_with_qualified(
789 &mut self,
790 self_ty: Ty<'tcx>,
791 trait_ref: Option<ty::TraitRef<'tcx>>,
792 ) -> Result<(), PrintError> {
793 if trait_ref.is_none()
794 && let ty::Adt(def, args) = self_ty.kind()
795 {
796 return self.print_def_path(def.did(), args);
797 }
798
799 with_no_trimmed_paths!({
801 self.path = vec![match trait_ref {
802 Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
803 None => Symbol::intern(&format!("<{self_ty}>")),
804 }];
805 Ok(())
806 })
807 }
808
809 fn print_path_with_impl(
810 &mut self,
811 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
812 self_ty: Ty<'tcx>,
813 trait_ref: Option<ty::TraitRef<'tcx>>,
814 ) -> Result<(), PrintError> {
815 print_prefix(self)?;
816
817 self.path.push(match trait_ref {
819 Some(trait_ref) => {
820 with_no_trimmed_paths!(Symbol::intern(&format!(
821 "<impl {} for {}>",
822 trait_ref.print_only_trait_path(),
823 self_ty
824 )))
825 }
826 None => {
827 with_no_trimmed_paths!(Symbol::intern(&format!("<impl {self_ty}>")))
828 }
829 });
830
831 Ok(())
832 }
833
834 fn print_path_with_simple(
835 &mut self,
836 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
837 disambiguated_data: &DisambiguatedDefPathData,
838 ) -> Result<(), PrintError> {
839 print_prefix(self)?;
840
841 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
843 return Ok(());
844 }
845
846 self.path.push(match disambiguated_data.data.get_opt_name() {
847 Some(sym) => sym,
848 None => Symbol::intern(&disambiguated_data.data.to_string()),
849 });
850 Ok(())
851 }
852
853 fn print_path_with_generic_args(
854 &mut self,
855 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
856 _args: &[GenericArg<'tcx>],
857 ) -> Result<(), PrintError> {
858 print_prefix(self)
859 }
860 }
861
862 let mut p = LintPathPrinter { tcx: self.tcx, path: vec![] };
863 p.print_def_path(def_id, &[]).unwrap();
864 p.path
865 }
866
867 pub fn get_associated_type(
870 &self,
871 self_ty: Ty<'tcx>,
872 trait_id: DefId,
873 name: Symbol,
874 ) -> Option<Ty<'tcx>> {
875 let tcx = self.tcx;
876 tcx.associated_items(trait_id)
877 .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
878 .and_then(|assoc| {
879 let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
880 tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()
881 })
882 }
883
884 pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
888 let has_attr = |id: hir::HirId| -> bool {
889 for attr in self.tcx.hir_attrs(id) {
890 if attr.span().desugaring_kind().is_none() {
891 return true;
892 }
893 }
894 false
895 };
896 expr.precedence(&has_attr)
897 }
898
899 pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
915 expr = expr.peel_blocks();
916
917 while let hir::ExprKind::Path(ref qpath) = expr.kind
918 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
919 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
920 _ => None,
921 }
922 && let Some(init) = match parent_node {
923 hir::Node::Expr(expr) => Some(expr),
924 hir::Node::LetStmt(hir::LetStmt {
925 init,
926 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
928 ..
929 }) => *init,
930 _ => None,
931 }
932 {
933 expr = init.peel_blocks();
934 }
935 expr
936 }
937
938 pub fn expr_or_init_with_outside_body<'a>(
961 &self,
962 mut expr: &'a hir::Expr<'tcx>,
963 ) -> &'a hir::Expr<'tcx> {
964 expr = expr.peel_blocks();
965
966 while let hir::ExprKind::Path(ref qpath) = expr.kind
967 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
968 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
969 Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
970 _ => None,
971 }
972 && let Some(init) = match parent_node {
973 hir::Node::Expr(expr) => Some(expr),
974 hir::Node::LetStmt(hir::LetStmt {
975 init,
976 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
978 ..
979 }) => *init,
980 hir::Node::Item(item) => match item.kind {
981 hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
982 Some(self.tcx.hir_body(body_id).value)
983 }
984 _ => None,
985 },
986 _ => None,
987 }
988 {
989 expr = init.peel_blocks();
990 }
991 expr
992 }
993}
994
995impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
996 #[inline]
997 fn data_layout(&self) -> &abi::TargetDataLayout {
998 &self.tcx.data_layout
999 }
1000}
1001
1002impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
1003 #[inline]
1004 fn tcx(&self) -> TyCtxt<'tcx> {
1005 self.tcx
1006 }
1007}
1008
1009impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
1010 #[inline]
1011 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
1012 self.typing_env()
1013 }
1014}
1015
1016impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
1017 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
1018
1019 #[inline]
1020 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
1021 err
1022 }
1023}