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
86struct LintAlias {
87 name: &'static str,
88 silent: bool,
90}
91
92struct LintGroup {
93 lint_ids: Vec<LintId>,
94 is_externally_loaded: bool,
95 depr: Option<LintAlias>,
96}
97
98#[derive(Debug)]
99pub enum CheckLintNameResult<'a> {
100 Ok(&'a [LintId]),
101 NoLint(Option<(Symbol, bool)>),
103 NoTool,
105 Renamed(String),
107 Removed(String),
109
110 Tool(&'a [LintId], Option<String>),
114
115 MissingTool,
119}
120
121impl LintStore {
122 pub fn new() -> LintStore {
123 LintStore {
124 lints: vec![],
125 pre_expansion_passes: vec![],
126 early_passes: vec![],
127 late_passes: vec![],
128 late_module_passes: vec![],
129 by_name: Default::default(),
130 lint_groups: Default::default(),
131 }
132 }
133
134 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
135 &self.lints
136 }
137
138 pub fn get_lint_groups(&self) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> {
139 self.lint_groups
140 .iter()
141 .filter(|(_, LintGroup { depr, .. })| {
142 depr.is_none()
144 })
145 .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
146 (*k, lint_ids.clone(), *is_externally_loaded)
147 })
148 }
149
150 pub fn register_early_pass(
151 &mut self,
152 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
153 ) {
154 self.early_passes.push(Box::new(pass));
155 }
156
157 pub fn register_pre_expansion_pass(
164 &mut self,
165 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
166 ) {
167 self.pre_expansion_passes.push(Box::new(pass));
168 }
169
170 pub fn register_late_pass(
171 &mut self,
172 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
173 + 'static
174 + sync::DynSend
175 + sync::DynSync,
176 ) {
177 self.late_passes.push(Box::new(pass));
178 }
179
180 pub fn register_late_mod_pass(
181 &mut self,
182 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
183 + 'static
184 + sync::DynSend
185 + sync::DynSync,
186 ) {
187 self.late_module_passes.push(Box::new(pass));
188 }
189
190 pub fn register_lints(&mut self, lints: &[&'static Lint]) {
192 for lint in lints {
193 self.lints.push(lint);
194
195 let id = LintId::of(lint);
196 if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
197 bug!("duplicate specification of lint {}", lint.name_lower())
198 }
199
200 if let Some(FutureIncompatibleInfo { reason, .. }) = lint.future_incompatible {
201 if let Some(edition) = reason.edition() {
202 self.lint_groups
203 .entry(edition.lint_name())
204 .or_insert(LintGroup {
205 lint_ids: vec![],
206 is_externally_loaded: lint.is_externally_loaded,
207 depr: None,
208 })
209 .lint_ids
210 .push(id);
211 } else {
212 self.lint_groups
216 .entry("future_incompatible")
217 .or_insert(LintGroup {
218 lint_ids: vec![],
219 is_externally_loaded: lint.is_externally_loaded,
220 depr: None,
221 })
222 .lint_ids
223 .push(id);
224 }
225 }
226 }
227 }
228
229 fn insert_group(&mut self, name: &'static str, group: LintGroup) {
230 let previous = self.lint_groups.insert(name, group);
231 if previous.is_some() {
232 bug!("group {name:?} already exists");
233 }
234 }
235
236 pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) {
237 let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else {
238 bug!("group alias {alias:?} points to unregistered group {group_name:?}")
239 };
240
241 self.insert_group(
242 alias,
243 LintGroup {
244 lint_ids: lint_ids.clone(),
245 is_externally_loaded: false,
246 depr: Some(LintAlias { name: group_name, silent: true }),
247 },
248 );
249 }
250
251 pub fn register_group(
252 &mut self,
253 is_externally_loaded: bool,
254 name: &'static str,
255 deprecated_name: Option<&'static str>,
256 to: Vec<LintId>,
257 ) {
258 if let Some(deprecated) = deprecated_name {
259 self.insert_group(
260 deprecated,
261 LintGroup {
262 lint_ids: to.clone(),
263 is_externally_loaded,
264 depr: Some(LintAlias { name, silent: false }),
265 },
266 );
267 }
268 self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None });
269 }
270
271 #[track_caller]
275 pub fn register_ignored(&mut self, name: &str) {
276 if self.by_name.insert(name.to_string(), Ignored).is_some() {
277 bug!("duplicate specification of lint {}", name);
278 }
279 }
280
281 #[track_caller]
283 pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
284 let Some(&Id(target)) = self.by_name.get(new_name) else {
285 bug!("invalid lint renaming of {} to {}", old_name, new_name);
286 };
287 self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
288 }
289
290 pub fn register_removed(&mut self, name: &str, reason: &str) {
291 self.by_name.insert(name.into(), Removed(reason.into()));
292 }
293
294 pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
295 match self.by_name.get(lint_name) {
296 Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
297 Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)),
298 Some(Removed(_)) => None,
299 Some(Ignored) => Some(&[]),
300 None => match self.lint_groups.get(lint_name) {
301 Some(LintGroup { lint_ids, .. }) => Some(lint_ids),
302 None => None,
303 },
304 }
305 }
306
307 pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
309 debug!(
310 "is_lint_group(lint_name={:?}, lint_groups={:?})",
311 lint_name,
312 self.lint_groups.keys().collect::<Vec<_>>()
313 );
314 let lint_name_str = lint_name.as_str();
315 self.lint_groups.contains_key(lint_name_str) || {
316 let warnings_name_str = crate::WARNINGS.name_lower();
317 lint_name_str == warnings_name_str
318 }
319 }
320
321 pub fn check_lint_name(
329 &self,
330 lint_name: &str,
331 tool_name: Option<Symbol>,
332 registered_tools: &RegisteredTools,
333 ) -> CheckLintNameResult<'_> {
334 if let Some(tool_name) = tool_name {
335 if tool_name != sym::rustc
337 && tool_name != sym::rustdoc
338 && !registered_tools.contains(&Ident::with_dummy_span(tool_name))
339 {
340 return CheckLintNameResult::NoTool;
341 }
342 }
343
344 let complete_name = if let Some(tool_name) = tool_name {
345 format!("{tool_name}::{lint_name}")
346 } else {
347 lint_name.to_string()
348 };
349 if let Some(tool_name) = tool_name {
351 match self.by_name.get(&complete_name) {
352 None => match self.lint_groups.get(&*complete_name) {
353 None => {
355 debug!("lints={:?}", self.by_name);
358 let tool_prefix = format!("{tool_name}::");
359
360 return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
361 self.no_lint_suggestion(&complete_name, tool_name.as_str())
362 } else {
363 CheckLintNameResult::MissingTool
366 };
367 }
368 Some(LintGroup { lint_ids, depr, .. }) => {
369 return if let &Some(LintAlias { name, silent: false }) = depr {
370 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
371 } else {
372 CheckLintNameResult::Tool(lint_ids, None)
373 };
374 }
375 },
376 Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
377 _ => {}
380 }
381 }
382 match self.by_name.get(&complete_name) {
383 Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
384 Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
385 None => match self.lint_groups.get(&*complete_name) {
386 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
389 Some(LintGroup { lint_ids, depr, .. }) => {
390 if let &Some(LintAlias { name, silent: false }) = depr {
392 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
393 } else {
394 CheckLintNameResult::Ok(lint_ids)
395 }
396 }
397 },
398 Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
399 Some(&Ignored) => CheckLintNameResult::Ok(&[]),
400 }
401 }
402
403 fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
404 let name_lower = lint_name.to_lowercase();
405
406 if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() {
407 return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
409 }
410
411 #[allow(rustc::potential_query_instability)]
417 let mut groups: Vec<_> = self
418 .lint_groups
419 .iter()
420 .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k))
421 .collect();
422 groups.sort();
423 let groups = groups.iter().map(|k| Symbol::intern(k));
424 let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
425 let names: Vec<Symbol> = groups.chain(lints).collect();
426 let mut lookups = vec![Symbol::intern(&name_lower)];
427 if let Some(stripped) = name_lower.split("::").last() {
428 lookups.push(Symbol::intern(stripped));
429 }
430 let res = find_best_match_for_names(&names, &lookups, None);
431 let is_rustc = res.map_or_else(
432 || false,
433 |s| name_lower.contains("::") && !s.as_str().starts_with(tool_name),
434 );
435 let suggestion = res.map(|s| (s, is_rustc));
436 CheckLintNameResult::NoLint(suggestion)
437 }
438
439 fn check_tool_name_for_backwards_compat(
440 &self,
441 lint_name: &str,
442 tool_name: &str,
443 ) -> CheckLintNameResult<'_> {
444 let complete_name = format!("{tool_name}::{lint_name}");
445 match self.by_name.get(&complete_name) {
446 None => match self.lint_groups.get(&*complete_name) {
447 None => self.no_lint_suggestion(lint_name, tool_name),
449 Some(LintGroup { lint_ids, .. }) => {
450 CheckLintNameResult::Tool(lint_ids, Some(complete_name))
451 }
452 },
453 Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)),
454 Some(other) => {
455 debug!("got renamed lint {:?}", other);
456 CheckLintNameResult::NoLint(None)
457 }
458 }
459 }
460}
461
462pub struct LateContext<'tcx> {
464 pub tcx: TyCtxt<'tcx>,
466
467 pub enclosing_body: Option<hir::BodyId>,
469
470 pub(super) cached_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
475
476 pub param_env: ty::ParamEnv<'tcx>,
478
479 pub effective_visibilities: &'tcx EffectiveVisibilities,
481
482 pub last_node_with_lint_attrs: hir::HirId,
483
484 pub generics: Option<&'tcx hir::Generics<'tcx>>,
486
487 pub only_module: bool,
489}
490
491pub struct EarlyContext<'a> {
493 pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>,
494 pub buffered: LintBuffer,
495}
496
497pub trait LintContext {
498 fn sess(&self) -> &Session;
499
500 #[rustc_lint_diagnostics]
506 fn opt_span_lint<S: Into<MultiSpan>>(
507 &self,
508 lint: &'static Lint,
509 span: Option<S>,
510 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
511 );
512
513 fn emit_span_lint<S: Into<MultiSpan>>(
516 &self,
517 lint: &'static Lint,
518 span: S,
519 decorator: impl for<'a> LintDiagnostic<'a, ()>,
520 ) {
521 self.opt_span_lint(lint, Some(span), |lint| {
522 decorator.decorate_lint(lint);
523 });
524 }
525
526 #[rustc_lint_diagnostics]
530 fn span_lint<S: Into<MultiSpan>>(
531 &self,
532 lint: &'static Lint,
533 span: S,
534 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
535 ) {
536 self.opt_span_lint(lint, Some(span), decorate);
537 }
538
539 fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> LintDiagnostic<'a, ()>) {
542 self.opt_span_lint(lint, None as Option<Span>, |lint| {
543 decorator.decorate_lint(lint);
544 });
545 }
546
547 #[rustc_lint_diagnostics]
551 fn lint(&self, lint: &'static Lint, decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>)) {
552 self.opt_span_lint(lint, None as Option<Span>, decorate);
553 }
554
555 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource;
557
558 fn fulfill_expectation(&self, expectation: LintExpectationId) {
566 #[allow(rustc::diagnostic_outside_of_impl)]
571 #[allow(rustc::untranslatable_diagnostic)]
572 self.sess()
573 .dcx()
574 .struct_expect(
575 "this is a dummy diagnostic, to submit and store an expectation",
576 expectation,
577 )
578 .emit();
579 }
580}
581
582impl<'a> EarlyContext<'a> {
583 pub(crate) fn new(
584 sess: &'a Session,
585 features: &'a Features,
586 lint_added_lints: bool,
587 lint_store: &'a LintStore,
588 registered_tools: &'a RegisteredTools,
589 buffered: LintBuffer,
590 ) -> EarlyContext<'a> {
591 EarlyContext {
592 builder: LintLevelsBuilder::new(
593 sess,
594 features,
595 lint_added_lints,
596 lint_store,
597 registered_tools,
598 ),
599 buffered,
600 }
601 }
602}
603
604impl<'tcx> LintContext for LateContext<'tcx> {
605 fn sess(&self) -> &Session {
607 self.tcx.sess
608 }
609
610 #[rustc_lint_diagnostics]
611 fn opt_span_lint<S: Into<MultiSpan>>(
612 &self,
613 lint: &'static Lint,
614 span: Option<S>,
615 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
616 ) {
617 let hir_id = self.last_node_with_lint_attrs;
618
619 match span {
620 Some(s) => self.tcx.node_span_lint(lint, hir_id, s, decorate),
621 None => self.tcx.node_lint(lint, hir_id, decorate),
622 }
623 }
624
625 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
626 self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs)
627 }
628}
629
630impl LintContext for EarlyContext<'_> {
631 fn sess(&self) -> &Session {
633 self.builder.sess()
634 }
635
636 #[rustc_lint_diagnostics]
637 fn opt_span_lint<S: Into<MultiSpan>>(
638 &self,
639 lint: &'static Lint,
640 span: Option<S>,
641 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
642 ) {
643 self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorate)
644 }
645
646 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
647 self.builder.lint_level(lint)
648 }
649}
650
651impl<'tcx> LateContext<'tcx> {
652 pub fn typing_mode(&self) -> TypingMode<'tcx> {
655 TypingMode::non_body_analysis()
658 }
659
660 pub fn typing_env(&self) -> TypingEnv<'tcx> {
661 TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
662 }
663
664 pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
665 self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
666 }
667
668 pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
669 self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
670 }
671
672 pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
675 self.cached_typeck_results.get().or_else(|| {
676 self.enclosing_body.map(|body| {
677 let typeck_results = self.tcx.typeck_body(body);
678 self.cached_typeck_results.set(Some(typeck_results));
679 typeck_results
680 })
681 })
682 }
683
684 #[track_caller]
688 pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
689 self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body")
690 }
691
692 pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
696 match *qpath {
697 hir::QPath::Resolved(_, path) => path.res,
698 hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
699 .maybe_typeck_results()
700 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
701 .or_else(|| {
702 self.tcx
703 .has_typeck_results(id.owner.def_id)
704 .then(|| self.tcx.typeck(id.owner.def_id))
705 })
706 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
707 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
708 }
709 }
710
711 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
722 struct AbsolutePathPrinter<'tcx> {
723 tcx: TyCtxt<'tcx>,
724 path: Vec<Symbol>,
725 }
726
727 impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
728 fn tcx(&self) -> TyCtxt<'tcx> {
729 self.tcx
730 }
731
732 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
733 Ok(())
734 }
735
736 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
737 Ok(())
738 }
739
740 fn print_dyn_existential(
741 &mut self,
742 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
743 ) -> Result<(), PrintError> {
744 Ok(())
745 }
746
747 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
748 Ok(())
749 }
750
751 fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
752 self.path = vec![self.tcx.crate_name(cnum)];
753 Ok(())
754 }
755
756 fn path_qualified(
757 &mut self,
758 self_ty: Ty<'tcx>,
759 trait_ref: Option<ty::TraitRef<'tcx>>,
760 ) -> Result<(), PrintError> {
761 if trait_ref.is_none() {
762 if let ty::Adt(def, args) = self_ty.kind() {
763 return self.print_def_path(def.did(), args);
764 }
765 }
766
767 with_no_trimmed_paths!({
769 self.path = vec![match trait_ref {
770 Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
771 None => Symbol::intern(&format!("<{self_ty}>")),
772 }];
773 Ok(())
774 })
775 }
776
777 fn path_append_impl(
778 &mut self,
779 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
780 _disambiguated_data: &DisambiguatedDefPathData,
781 self_ty: Ty<'tcx>,
782 trait_ref: Option<ty::TraitRef<'tcx>>,
783 ) -> Result<(), PrintError> {
784 print_prefix(self)?;
785
786 self.path.push(match trait_ref {
788 Some(trait_ref) => {
789 with_no_trimmed_paths!(Symbol::intern(&format!(
790 "<impl {} for {}>",
791 trait_ref.print_only_trait_path(),
792 self_ty
793 )))
794 }
795 None => {
796 with_no_trimmed_paths!(Symbol::intern(&format!("<impl {self_ty}>")))
797 }
798 });
799
800 Ok(())
801 }
802
803 fn path_append(
804 &mut self,
805 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
806 disambiguated_data: &DisambiguatedDefPathData,
807 ) -> Result<(), PrintError> {
808 print_prefix(self)?;
809
810 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
812 return Ok(());
813 }
814
815 self.path.push(Symbol::intern(&disambiguated_data.data.to_string()));
816 Ok(())
817 }
818
819 fn path_generic_args(
820 &mut self,
821 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
822 _args: &[GenericArg<'tcx>],
823 ) -> Result<(), PrintError> {
824 print_prefix(self)
825 }
826 }
827
828 let mut printer = AbsolutePathPrinter { tcx: self.tcx, path: vec![] };
829 printer.print_def_path(def_id, &[]).unwrap();
830 printer.path
831 }
832
833 pub fn get_associated_type(
836 &self,
837 self_ty: Ty<'tcx>,
838 trait_id: DefId,
839 name: Symbol,
840 ) -> Option<Ty<'tcx>> {
841 let tcx = self.tcx;
842 tcx.associated_items(trait_id)
843 .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
844 .and_then(|assoc| {
845 let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
846 tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()
847 })
848 }
849
850 pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
866 expr = expr.peel_blocks();
867
868 while let hir::ExprKind::Path(ref qpath) = expr.kind
869 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
870 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
871 _ => None,
872 }
873 && let Some(init) = match parent_node {
874 hir::Node::Expr(expr) => Some(expr),
875 hir::Node::LetStmt(hir::LetStmt {
876 init,
877 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
879 ..
880 }) => *init,
881 _ => None,
882 }
883 {
884 expr = init.peel_blocks();
885 }
886 expr
887 }
888
889 pub fn expr_or_init_with_outside_body<'a>(
912 &self,
913 mut expr: &'a hir::Expr<'tcx>,
914 ) -> &'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 Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
921 _ => None,
922 }
923 && let Some(init) = match parent_node {
924 hir::Node::Expr(expr) => Some(expr),
925 hir::Node::LetStmt(hir::LetStmt {
926 init,
927 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
929 ..
930 }) => *init,
931 hir::Node::Item(item) => match item.kind {
932 hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
933 Some(self.tcx.hir_body(body_id).value)
934 }
935 _ => None,
936 },
937 _ => None,
938 }
939 {
940 expr = init.peel_blocks();
941 }
942 expr
943 }
944}
945
946impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
947 #[inline]
948 fn data_layout(&self) -> &abi::TargetDataLayout {
949 &self.tcx.data_layout
950 }
951}
952
953impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
954 #[inline]
955 fn tcx(&self) -> TyCtxt<'tcx> {
956 self.tcx
957 }
958}
959
960impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
961 #[inline]
962 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
963 self.typing_env()
964 }
965}
966
967impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
968 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
969
970 #[inline]
971 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
972 err
973 }
974}