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