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(..) => 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}