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::middle::privacy::EffectiveVisibilities;
21use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
22use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
23use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode};
24use rustc_session::lint::{
25 FutureIncompatibleInfo, Level, Lint, LintBuffer, LintExpectationId, LintId,
26};
27use rustc_session::{LintStoreMarker, 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 LintStoreMarker for LintStore {}
66
67#[derive(Debug)]
69enum TargetLint {
70 Id(LintId),
72
73 Renamed(String, LintId),
75
76 Removed(String),
79
80 Ignored,
85}
86
87pub enum FindLintError {
88 NotFound,
89 Removed,
90}
91
92struct LintAlias {
93 name: &'static str,
94 silent: bool,
96}
97
98struct LintGroup {
99 lint_ids: Vec<LintId>,
100 is_externally_loaded: bool,
101 depr: Option<LintAlias>,
102}
103
104#[derive(Debug)]
105pub enum CheckLintNameResult<'a> {
106 Ok(&'a [LintId]),
107 NoLint(Option<(Symbol, bool)>),
109 NoTool,
111 Renamed(String),
113 Removed(String),
115
116 Tool(&'a [LintId], Option<String>),
120
121 MissingTool,
125}
126
127impl LintStore {
128 pub fn new() -> LintStore {
129 LintStore {
130 lints: vec![],
131 pre_expansion_passes: vec![],
132 early_passes: vec![],
133 late_passes: vec![],
134 late_module_passes: vec![],
135 by_name: Default::default(),
136 lint_groups: Default::default(),
137 }
138 }
139
140 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
141 &self.lints
142 }
143
144 pub fn get_lint_groups(&self) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> {
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 type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
689 self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
690 }
691
692 pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
695 self.cached_typeck_results.get().or_else(|| {
696 self.enclosing_body.map(|body| {
697 let typeck_results = self.tcx.typeck_body(body);
698 self.cached_typeck_results.set(Some(typeck_results));
699 typeck_results
700 })
701 })
702 }
703
704 #[track_caller]
708 pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
709 self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body")
710 }
711
712 pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
716 match *qpath {
717 hir::QPath::Resolved(_, path) => path.res,
718 hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
719 .maybe_typeck_results()
720 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
721 .or_else(|| {
722 self.tcx
723 .has_typeck_results(id.owner.def_id)
724 .then(|| self.tcx.typeck(id.owner.def_id))
725 })
726 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
727 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
728 }
729 }
730
731 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
742 struct AbsolutePathPrinter<'tcx> {
743 tcx: TyCtxt<'tcx>,
744 path: Vec<Symbol>,
745 }
746
747 impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
748 fn tcx(&self) -> TyCtxt<'tcx> {
749 self.tcx
750 }
751
752 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
753 Ok(())
754 }
755
756 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
757 Ok(())
758 }
759
760 fn print_dyn_existential(
761 &mut self,
762 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
763 ) -> Result<(), PrintError> {
764 Ok(())
765 }
766
767 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
768 Ok(())
769 }
770
771 fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
772 self.path = vec![self.tcx.crate_name(cnum)];
773 Ok(())
774 }
775
776 fn path_qualified(
777 &mut self,
778 self_ty: Ty<'tcx>,
779 trait_ref: Option<ty::TraitRef<'tcx>>,
780 ) -> Result<(), PrintError> {
781 if trait_ref.is_none() {
782 if let ty::Adt(def, args) = self_ty.kind() {
783 return self.print_def_path(def.did(), args);
784 }
785 }
786
787 with_no_trimmed_paths!({
789 self.path = vec![match trait_ref {
790 Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
791 None => Symbol::intern(&format!("<{self_ty}>")),
792 }];
793 Ok(())
794 })
795 }
796
797 fn path_append_impl(
798 &mut self,
799 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
800 _disambiguated_data: &DisambiguatedDefPathData,
801 self_ty: Ty<'tcx>,
802 trait_ref: Option<ty::TraitRef<'tcx>>,
803 ) -> Result<(), PrintError> {
804 print_prefix(self)?;
805
806 self.path.push(match trait_ref {
808 Some(trait_ref) => {
809 with_no_trimmed_paths!(Symbol::intern(&format!(
810 "<impl {} for {}>",
811 trait_ref.print_only_trait_path(),
812 self_ty
813 )))
814 }
815 None => {
816 with_no_trimmed_paths!(Symbol::intern(&format!("<impl {self_ty}>")))
817 }
818 });
819
820 Ok(())
821 }
822
823 fn path_append(
824 &mut self,
825 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
826 disambiguated_data: &DisambiguatedDefPathData,
827 ) -> Result<(), PrintError> {
828 print_prefix(self)?;
829
830 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
832 return Ok(());
833 }
834
835 self.path.push(Symbol::intern(&disambiguated_data.data.to_string()));
836 Ok(())
837 }
838
839 fn path_generic_args(
840 &mut self,
841 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
842 _args: &[GenericArg<'tcx>],
843 ) -> Result<(), PrintError> {
844 print_prefix(self)
845 }
846 }
847
848 let mut printer = AbsolutePathPrinter { tcx: self.tcx, path: vec![] };
849 printer.print_def_path(def_id, &[]).unwrap();
850 printer.path
851 }
852
853 pub fn get_associated_type(
856 &self,
857 self_ty: Ty<'tcx>,
858 trait_id: DefId,
859 name: &str,
860 ) -> Option<Ty<'tcx>> {
861 let tcx = self.tcx;
862 tcx.associated_items(trait_id)
863 .find_by_name_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
864 .and_then(|assoc| {
865 let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
866 tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()
867 })
868 }
869
870 pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
886 expr = expr.peel_blocks();
887
888 while let hir::ExprKind::Path(ref qpath) = expr.kind
889 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
890 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
891 _ => None,
892 }
893 && let Some(init) = match parent_node {
894 hir::Node::Expr(expr) => Some(expr),
895 hir::Node::LetStmt(hir::LetStmt {
896 init,
897 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
899 ..
900 }) => *init,
901 _ => None,
902 }
903 {
904 expr = init.peel_blocks();
905 }
906 expr
907 }
908
909 pub fn expr_or_init_with_outside_body<'a>(
932 &self,
933 mut expr: &'a hir::Expr<'tcx>,
934 ) -> &'a hir::Expr<'tcx> {
935 expr = expr.peel_blocks();
936
937 while let hir::ExprKind::Path(ref qpath) = expr.kind
938 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
939 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
940 Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
941 _ => None,
942 }
943 && let Some(init) = match parent_node {
944 hir::Node::Expr(expr) => Some(expr),
945 hir::Node::LetStmt(hir::LetStmt {
946 init,
947 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
949 ..
950 }) => *init,
951 hir::Node::Item(item) => match item.kind {
952 hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
953 Some(self.tcx.hir_body(body_id).value)
954 }
955 _ => None,
956 },
957 _ => None,
958 }
959 {
960 expr = init.peel_blocks();
961 }
962 expr
963 }
964}
965
966impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
967 #[inline]
968 fn data_layout(&self) -> &abi::TargetDataLayout {
969 &self.tcx.data_layout
970 }
971}
972
973impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
974 #[inline]
975 fn tcx(&self) -> TyCtxt<'tcx> {
976 self.tcx
977 }
978}
979
980impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
981 #[inline]
982 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
983 self.typing_env()
984 }
985}
986
987impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
988 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
989
990 #[inline]
991 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
992 err
993 }
994}