1use std::cell::Cell;
7use std::slice;
8
9use rustc_ast::BindingMode;
10use rustc_data_structures::fx::FxIndexMap;
11use rustc_data_structures::sync;
12use rustc_data_structures::unord::UnordMap;
13use rustc_errors::{Diag, LintDiagnostic, MultiSpan};
14use rustc_feature::Features;
15use rustc_hir::def::Res;
16use rustc_hir::def_id::{CrateNum, DefId};
17use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
18use rustc_hir::{Pat, PatKind};
19use rustc_middle::bug;
20use rustc_middle::lint::LevelAndSource;
21use rustc_middle::middle::privacy::EffectiveVisibilities;
22use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
23use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
24use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode};
25use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintBuffer, LintExpectationId, LintId};
26use rustc_session::{LintStoreMarker, Session};
27use rustc_span::edit_distance::find_best_match_for_names;
28use rustc_span::{Ident, Span, Symbol, sym};
29use tracing::debug;
30use {rustc_abi as abi, rustc_hir as hir};
31
32use self::TargetLint::*;
33use crate::levels::LintLevelsBuilder;
34use crate::passes::{EarlyLintPassObject, LateLintPassObject};
35
36type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync;
37type LateLintPassFactory =
38 dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
39
40pub struct LintStore {
42 lints: Vec<&'static Lint>,
44
45 pub pre_expansion_passes: Vec<Box<EarlyLintPassFactory>>,
52 pub early_passes: Vec<Box<EarlyLintPassFactory>>,
53 pub late_passes: Vec<Box<LateLintPassFactory>>,
54 pub late_module_passes: Vec<Box<LateLintPassFactory>>,
56
57 by_name: UnordMap<String, TargetLint>,
59
60 lint_groups: FxIndexMap<&'static str, LintGroup>,
62}
63
64impl LintStoreMarker for LintStore {}
65
66#[derive(Debug)]
68enum TargetLint {
69 Id(LintId),
71
72 Renamed(String, LintId),
74
75 Removed(String),
78
79 Ignored,
84}
85
86pub enum FindLintError {
87 NotFound,
88 Removed,
89}
90
91struct LintAlias {
92 name: &'static str,
93 silent: bool,
95}
96
97struct LintGroup {
98 lint_ids: Vec<LintId>,
99 is_externally_loaded: bool,
100 depr: Option<LintAlias>,
101}
102
103#[derive(Debug)]
104pub enum CheckLintNameResult<'a> {
105 Ok(&'a [LintId]),
106 NoLint(Option<(Symbol, bool)>),
108 NoTool,
110 Renamed(String),
112 Removed(String),
114
115 Tool(&'a [LintId], Option<String>),
119
120 MissingTool,
124}
125
126impl LintStore {
127 pub fn new() -> LintStore {
128 LintStore {
129 lints: vec![],
130 pre_expansion_passes: vec![],
131 early_passes: vec![],
132 late_passes: vec![],
133 late_module_passes: vec![],
134 by_name: Default::default(),
135 lint_groups: Default::default(),
136 }
137 }
138
139 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
140 &self.lints
141 }
142
143 pub fn get_lint_groups(&self) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> {
144 self.lint_groups
145 .iter()
146 .filter(|(_, LintGroup { depr, .. })| {
147 depr.is_none()
149 })
150 .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
151 (*k, lint_ids.clone(), *is_externally_loaded)
152 })
153 }
154
155 pub fn register_early_pass(
156 &mut self,
157 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
158 ) {
159 self.early_passes.push(Box::new(pass));
160 }
161
162 pub fn register_pre_expansion_pass(
169 &mut self,
170 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
171 ) {
172 self.pre_expansion_passes.push(Box::new(pass));
173 }
174
175 pub fn register_late_pass(
176 &mut self,
177 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
178 + 'static
179 + sync::DynSend
180 + sync::DynSync,
181 ) {
182 self.late_passes.push(Box::new(pass));
183 }
184
185 pub fn register_late_mod_pass(
186 &mut self,
187 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
188 + 'static
189 + sync::DynSend
190 + sync::DynSync,
191 ) {
192 self.late_module_passes.push(Box::new(pass));
193 }
194
195 pub fn register_lints(&mut self, lints: &[&'static Lint]) {
197 for lint in lints {
198 self.lints.push(lint);
199
200 let id = LintId::of(lint);
201 if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
202 bug!("duplicate specification of lint {}", lint.name_lower())
203 }
204
205 if let Some(FutureIncompatibleInfo { reason, .. }) = lint.future_incompatible {
206 if let Some(edition) = reason.edition() {
207 self.lint_groups
208 .entry(edition.lint_name())
209 .or_insert(LintGroup {
210 lint_ids: vec![],
211 is_externally_loaded: lint.is_externally_loaded,
212 depr: None,
213 })
214 .lint_ids
215 .push(id);
216 } else {
217 self.lint_groups
221 .entry("future_incompatible")
222 .or_insert(LintGroup {
223 lint_ids: vec![],
224 is_externally_loaded: lint.is_externally_loaded,
225 depr: None,
226 })
227 .lint_ids
228 .push(id);
229 }
230 }
231 }
232 }
233
234 pub fn register_group_alias(&mut self, lint_name: &'static str, alias: &'static str) {
235 self.lint_groups.insert(
236 alias,
237 LintGroup {
238 lint_ids: vec![],
239 is_externally_loaded: false,
240 depr: Some(LintAlias { name: lint_name, silent: true }),
241 },
242 );
243 }
244
245 pub fn register_group(
246 &mut self,
247 is_externally_loaded: bool,
248 name: &'static str,
249 deprecated_name: Option<&'static str>,
250 to: Vec<LintId>,
251 ) {
252 let new = self
253 .lint_groups
254 .insert(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None })
255 .is_none();
256 if let Some(deprecated) = deprecated_name {
257 self.lint_groups.insert(
258 deprecated,
259 LintGroup {
260 lint_ids: vec![],
261 is_externally_loaded,
262 depr: Some(LintAlias { name, silent: false }),
263 },
264 );
265 }
266
267 if !new {
268 bug!("duplicate specification of lint group {}", name);
269 }
270 }
271
272 #[track_caller]
276 pub fn register_ignored(&mut self, name: &str) {
277 if self.by_name.insert(name.to_string(), Ignored).is_some() {
278 bug!("duplicate specification of lint {}", name);
279 }
280 }
281
282 #[track_caller]
284 pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
285 let Some(&Id(target)) = self.by_name.get(new_name) else {
286 bug!("invalid lint renaming of {} to {}", old_name, new_name);
287 };
288 self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
289 }
290
291 pub fn register_removed(&mut self, name: &str, reason: &str) {
292 self.by_name.insert(name.into(), Removed(reason.into()));
293 }
294
295 pub fn find_lints(&self, mut lint_name: &str) -> Result<Vec<LintId>, FindLintError> {
296 match self.by_name.get(lint_name) {
297 Some(&Id(lint_id)) => Ok(vec![lint_id]),
298 Some(&Renamed(_, lint_id)) => Ok(vec![lint_id]),
299 Some(&Removed(_)) => Err(FindLintError::Removed),
300 Some(&Ignored) => Ok(vec![]),
301 None => loop {
302 return match self.lint_groups.get(lint_name) {
303 Some(LintGroup { lint_ids, depr, .. }) => {
304 if let Some(LintAlias { name, .. }) = depr {
305 lint_name = name;
306 continue;
307 }
308 Ok(lint_ids.clone())
309 }
310 None => Err(FindLintError::Removed),
311 };
312 },
313 }
314 }
315
316 pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
318 debug!(
319 "is_lint_group(lint_name={:?}, lint_groups={:?})",
320 lint_name,
321 self.lint_groups.keys().collect::<Vec<_>>()
322 );
323 let lint_name_str = lint_name.as_str();
324 self.lint_groups.contains_key(lint_name_str) || {
325 let warnings_name_str = crate::WARNINGS.name_lower();
326 lint_name_str == warnings_name_str
327 }
328 }
329
330 pub fn check_lint_name(
338 &self,
339 lint_name: &str,
340 tool_name: Option<Symbol>,
341 registered_tools: &RegisteredTools,
342 ) -> CheckLintNameResult<'_> {
343 if let Some(tool_name) = tool_name {
344 if tool_name != sym::rustc
346 && tool_name != sym::rustdoc
347 && !registered_tools.contains(&Ident::with_dummy_span(tool_name))
348 {
349 return CheckLintNameResult::NoTool;
350 }
351 }
352
353 let complete_name = if let Some(tool_name) = tool_name {
354 format!("{tool_name}::{lint_name}")
355 } else {
356 lint_name.to_string()
357 };
358 if let Some(tool_name) = tool_name {
360 match self.by_name.get(&complete_name) {
361 None => match self.lint_groups.get(&*complete_name) {
362 None => {
364 debug!("lints={:?}", self.by_name);
367 let tool_prefix = format!("{tool_name}::");
368
369 return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
370 self.no_lint_suggestion(&complete_name, tool_name.as_str())
371 } else {
372 CheckLintNameResult::MissingTool
375 };
376 }
377 Some(LintGroup { lint_ids, .. }) => {
378 return CheckLintNameResult::Tool(lint_ids, None);
379 }
380 },
381 Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
382 _ => {}
385 }
386 }
387 match self.by_name.get(&complete_name) {
388 Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
389 Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
390 None => match self.lint_groups.get(&*complete_name) {
391 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
394 Some(LintGroup { lint_ids, depr, .. }) => {
395 if let Some(LintAlias { name, silent }) = depr {
397 let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
398 return if *silent {
399 CheckLintNameResult::Ok(lint_ids)
400 } else {
401 CheckLintNameResult::Tool(lint_ids, Some((*name).to_string()))
402 };
403 }
404 CheckLintNameResult::Ok(lint_ids)
405 }
406 },
407 Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
408 Some(&Ignored) => CheckLintNameResult::Ok(&[]),
409 }
410 }
411
412 fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
413 let name_lower = lint_name.to_lowercase();
414
415 if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_ok() {
416 return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
418 }
419
420 #[allow(rustc::potential_query_instability)]
426 let mut groups: Vec<_> = self
427 .lint_groups
428 .iter()
429 .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k))
430 .collect();
431 groups.sort();
432 let groups = groups.iter().map(|k| Symbol::intern(k));
433 let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
434 let names: Vec<Symbol> = groups.chain(lints).collect();
435 let mut lookups = vec![Symbol::intern(&name_lower)];
436 if let Some(stripped) = name_lower.split("::").last() {
437 lookups.push(Symbol::intern(stripped));
438 }
439 let res = find_best_match_for_names(&names, &lookups, None);
440 let is_rustc = res.map_or_else(
441 || false,
442 |s| name_lower.contains("::") && !s.as_str().starts_with(tool_name),
443 );
444 let suggestion = res.map(|s| (s, is_rustc));
445 CheckLintNameResult::NoLint(suggestion)
446 }
447
448 fn check_tool_name_for_backwards_compat(
449 &self,
450 lint_name: &str,
451 tool_name: &str,
452 ) -> CheckLintNameResult<'_> {
453 let complete_name = format!("{tool_name}::{lint_name}");
454 match self.by_name.get(&complete_name) {
455 None => match self.lint_groups.get(&*complete_name) {
456 None => self.no_lint_suggestion(lint_name, tool_name),
458 Some(LintGroup { lint_ids, depr, .. }) => {
459 if let Some(LintAlias { name, silent }) = depr {
461 let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
462 if *silent {
463 CheckLintNameResult::Tool(lint_ids, Some(complete_name))
464 } else {
465 CheckLintNameResult::Tool(lint_ids, Some((*name).to_string()))
466 }
467 } else {
468 CheckLintNameResult::Tool(lint_ids, Some(complete_name))
469 }
470 }
471 },
472 Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)),
473 Some(other) => {
474 debug!("got renamed lint {:?}", other);
475 CheckLintNameResult::NoLint(None)
476 }
477 }
478 }
479}
480
481pub struct LateContext<'tcx> {
483 pub tcx: TyCtxt<'tcx>,
485
486 pub enclosing_body: Option<hir::BodyId>,
488
489 pub(super) cached_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
494
495 pub param_env: ty::ParamEnv<'tcx>,
497
498 pub effective_visibilities: &'tcx EffectiveVisibilities,
500
501 pub last_node_with_lint_attrs: hir::HirId,
502
503 pub generics: Option<&'tcx hir::Generics<'tcx>>,
505
506 pub only_module: bool,
508}
509
510pub struct EarlyContext<'a> {
512 pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>,
513 pub buffered: LintBuffer,
514}
515
516pub trait LintContext {
517 fn sess(&self) -> &Session;
518
519 #[rustc_lint_diagnostics]
525 fn opt_span_lint<S: Into<MultiSpan>>(
526 &self,
527 lint: &'static Lint,
528 span: Option<S>,
529 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
530 );
531
532 fn emit_span_lint<S: Into<MultiSpan>>(
535 &self,
536 lint: &'static Lint,
537 span: S,
538 decorator: impl for<'a> LintDiagnostic<'a, ()>,
539 ) {
540 self.opt_span_lint(lint, Some(span), |lint| {
541 decorator.decorate_lint(lint);
542 });
543 }
544
545 #[rustc_lint_diagnostics]
549 fn span_lint<S: Into<MultiSpan>>(
550 &self,
551 lint: &'static Lint,
552 span: S,
553 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
554 ) {
555 self.opt_span_lint(lint, Some(span), decorate);
556 }
557
558 fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> LintDiagnostic<'a, ()>) {
561 self.opt_span_lint(lint, None as Option<Span>, |lint| {
562 decorator.decorate_lint(lint);
563 });
564 }
565
566 #[rustc_lint_diagnostics]
570 fn lint(&self, lint: &'static Lint, decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>)) {
571 self.opt_span_lint(lint, None as Option<Span>, decorate);
572 }
573
574 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource;
576
577 fn fulfill_expectation(&self, expectation: LintExpectationId) {
585 #[allow(rustc::diagnostic_outside_of_impl)]
590 #[allow(rustc::untranslatable_diagnostic)]
591 self.sess()
592 .dcx()
593 .struct_expect(
594 "this is a dummy diagnostic, to submit and store an expectation",
595 expectation,
596 )
597 .emit();
598 }
599}
600
601impl<'a> EarlyContext<'a> {
602 pub(crate) fn new(
603 sess: &'a Session,
604 features: &'a Features,
605 lint_added_lints: bool,
606 lint_store: &'a LintStore,
607 registered_tools: &'a RegisteredTools,
608 buffered: LintBuffer,
609 ) -> EarlyContext<'a> {
610 EarlyContext {
611 builder: LintLevelsBuilder::new(
612 sess,
613 features,
614 lint_added_lints,
615 lint_store,
616 registered_tools,
617 ),
618 buffered,
619 }
620 }
621}
622
623impl<'tcx> LintContext for LateContext<'tcx> {
624 fn sess(&self) -> &Session {
626 self.tcx.sess
627 }
628
629 #[rustc_lint_diagnostics]
630 fn opt_span_lint<S: Into<MultiSpan>>(
631 &self,
632 lint: &'static Lint,
633 span: Option<S>,
634 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
635 ) {
636 let hir_id = self.last_node_with_lint_attrs;
637
638 match span {
639 Some(s) => self.tcx.node_span_lint(lint, hir_id, s, decorate),
640 None => self.tcx.node_lint(lint, hir_id, decorate),
641 }
642 }
643
644 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
645 self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs)
646 }
647}
648
649impl LintContext for EarlyContext<'_> {
650 fn sess(&self) -> &Session {
652 self.builder.sess()
653 }
654
655 #[rustc_lint_diagnostics]
656 fn opt_span_lint<S: Into<MultiSpan>>(
657 &self,
658 lint: &'static Lint,
659 span: Option<S>,
660 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
661 ) {
662 self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorate)
663 }
664
665 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
666 self.builder.lint_level(lint)
667 }
668}
669
670impl<'tcx> LateContext<'tcx> {
671 pub fn typing_mode(&self) -> TypingMode<'tcx> {
674 TypingMode::non_body_analysis()
677 }
678
679 pub fn typing_env(&self) -> TypingEnv<'tcx> {
680 TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
681 }
682
683 pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
684 self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
685 }
686
687 pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
688 self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
689 }
690
691 pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
694 self.cached_typeck_results.get().or_else(|| {
695 self.enclosing_body.map(|body| {
696 let typeck_results = self.tcx.typeck_body(body);
697 self.cached_typeck_results.set(Some(typeck_results));
698 typeck_results
699 })
700 })
701 }
702
703 #[track_caller]
707 pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
708 self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body")
709 }
710
711 pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
715 match *qpath {
716 hir::QPath::Resolved(_, path) => path.res,
717 hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
718 .maybe_typeck_results()
719 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
720 .or_else(|| {
721 self.tcx
722 .has_typeck_results(id.owner.def_id)
723 .then(|| self.tcx.typeck(id.owner.def_id))
724 })
725 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
726 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
727 }
728 }
729
730 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
741 struct AbsolutePathPrinter<'tcx> {
742 tcx: TyCtxt<'tcx>,
743 path: Vec<Symbol>,
744 }
745
746 impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
747 fn tcx(&self) -> TyCtxt<'tcx> {
748 self.tcx
749 }
750
751 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
752 Ok(())
753 }
754
755 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
756 Ok(())
757 }
758
759 fn print_dyn_existential(
760 &mut self,
761 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
762 ) -> Result<(), PrintError> {
763 Ok(())
764 }
765
766 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
767 Ok(())
768 }
769
770 fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
771 self.path = vec![self.tcx.crate_name(cnum)];
772 Ok(())
773 }
774
775 fn path_qualified(
776 &mut self,
777 self_ty: Ty<'tcx>,
778 trait_ref: Option<ty::TraitRef<'tcx>>,
779 ) -> Result<(), PrintError> {
780 if trait_ref.is_none() {
781 if let ty::Adt(def, args) = self_ty.kind() {
782 return self.print_def_path(def.did(), args);
783 }
784 }
785
786 with_no_trimmed_paths!({
788 self.path = vec![match trait_ref {
789 Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
790 None => Symbol::intern(&format!("<{self_ty}>")),
791 }];
792 Ok(())
793 })
794 }
795
796 fn path_append_impl(
797 &mut self,
798 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
799 _disambiguated_data: &DisambiguatedDefPathData,
800 self_ty: Ty<'tcx>,
801 trait_ref: Option<ty::TraitRef<'tcx>>,
802 ) -> Result<(), PrintError> {
803 print_prefix(self)?;
804
805 self.path.push(match trait_ref {
807 Some(trait_ref) => {
808 with_no_trimmed_paths!(Symbol::intern(&format!(
809 "<impl {} for {}>",
810 trait_ref.print_only_trait_path(),
811 self_ty
812 )))
813 }
814 None => {
815 with_no_trimmed_paths!(Symbol::intern(&format!("<impl {self_ty}>")))
816 }
817 });
818
819 Ok(())
820 }
821
822 fn path_append(
823 &mut self,
824 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
825 disambiguated_data: &DisambiguatedDefPathData,
826 ) -> Result<(), PrintError> {
827 print_prefix(self)?;
828
829 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
831 return Ok(());
832 }
833
834 self.path.push(Symbol::intern(&disambiguated_data.data.to_string()));
835 Ok(())
836 }
837
838 fn path_generic_args(
839 &mut self,
840 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
841 _args: &[GenericArg<'tcx>],
842 ) -> Result<(), PrintError> {
843 print_prefix(self)
844 }
845 }
846
847 let mut printer = AbsolutePathPrinter { tcx: self.tcx, path: vec![] };
848 printer.print_def_path(def_id, &[]).unwrap();
849 printer.path
850 }
851
852 pub fn get_associated_type(
855 &self,
856 self_ty: Ty<'tcx>,
857 trait_id: DefId,
858 name: &str,
859 ) -> Option<Ty<'tcx>> {
860 let tcx = self.tcx;
861 tcx.associated_items(trait_id)
862 .find_by_ident_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
863 .and_then(|assoc| {
864 let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
865 tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()
866 })
867 }
868
869 pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
885 expr = expr.peel_blocks();
886
887 while let hir::ExprKind::Path(ref qpath) = expr.kind
888 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
889 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
890 _ => None,
891 }
892 && let Some(init) = match parent_node {
893 hir::Node::Expr(expr) => Some(expr),
894 hir::Node::LetStmt(hir::LetStmt {
895 init,
896 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
898 ..
899 }) => *init,
900 _ => None,
901 }
902 {
903 expr = init.peel_blocks();
904 }
905 expr
906 }
907
908 pub fn expr_or_init_with_outside_body<'a>(
931 &self,
932 mut expr: &'a hir::Expr<'tcx>,
933 ) -> &'a hir::Expr<'tcx> {
934 expr = expr.peel_blocks();
935
936 while let hir::ExprKind::Path(ref qpath) = expr.kind
937 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
938 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
939 Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
940 _ => None,
941 }
942 && let Some(init) = match parent_node {
943 hir::Node::Expr(expr) => Some(expr),
944 hir::Node::LetStmt(hir::LetStmt {
945 init,
946 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
948 ..
949 }) => *init,
950 hir::Node::Item(item) => match item.kind {
951 hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
952 Some(self.tcx.hir_body(body_id).value)
953 }
954 _ => None,
955 },
956 _ => None,
957 }
958 {
959 expr = init.peel_blocks();
960 }
961 expr
962 }
963}
964
965impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
966 #[inline]
967 fn data_layout(&self) -> &abi::TargetDataLayout {
968 &self.tcx.data_layout
969 }
970}
971
972impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
973 #[inline]
974 fn tcx(&self) -> TyCtxt<'tcx> {
975 self.tcx
976 }
977}
978
979impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
980 #[inline]
981 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
982 self.typing_env()
983 }
984}
985
986impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
987 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
988
989 #[inline]
990 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
991 err
992 }
993}