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, 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, LintBuffer, LintExpectationId, LintId};
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
87struct LintAlias {
88 name: &'static str,
89 silent: bool,
91}
92
93struct LintGroup {
94 lint_ids: Vec<LintId>,
95 is_externally_loaded: bool,
96 depr: Option<LintAlias>,
97}
98
99#[derive(Debug)]
100pub enum CheckLintNameResult<'a> {
101 Ok(&'a [LintId]),
102 NoLint(Option<(Symbol, bool)>),
104 NoTool,
106 Renamed(String),
108 Removed(String),
110
111 Tool(&'a [LintId], Option<String>),
115
116 MissingTool,
120}
121
122impl LintStore {
123 pub fn new() -> LintStore {
124 LintStore {
125 lints: vec![],
126 pre_expansion_passes: vec![],
127 early_passes: vec![],
128 late_passes: vec![],
129 late_module_passes: vec![],
130 by_name: Default::default(),
131 lint_groups: Default::default(),
132 }
133 }
134
135 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
136 &self.lints
137 }
138
139 pub fn get_lint_groups(&self) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> {
140 self.lint_groups
141 .iter()
142 .filter(|(_, LintGroup { depr, .. })| {
143 depr.is_none()
145 })
146 .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
147 (*k, lint_ids.clone(), *is_externally_loaded)
148 })
149 }
150
151 pub fn register_early_pass(
152 &mut self,
153 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
154 ) {
155 self.early_passes.push(Box::new(pass));
156 }
157
158 pub fn register_pre_expansion_pass(
165 &mut self,
166 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
167 ) {
168 self.pre_expansion_passes.push(Box::new(pass));
169 }
170
171 pub fn register_late_pass(
172 &mut self,
173 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
174 + 'static
175 + sync::DynSend
176 + sync::DynSync,
177 ) {
178 self.late_passes.push(Box::new(pass));
179 }
180
181 pub fn register_late_mod_pass(
182 &mut self,
183 pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
184 + 'static
185 + sync::DynSend
186 + sync::DynSync,
187 ) {
188 self.late_module_passes.push(Box::new(pass));
189 }
190
191 pub fn register_lints(&mut self, lints: &[&'static Lint]) {
193 for lint in lints {
194 self.lints.push(lint);
195
196 let id = LintId::of(lint);
197 if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
198 bug!("duplicate specification of lint {}", lint.name_lower())
199 }
200
201 if let Some(FutureIncompatibleInfo { reason, .. }) = lint.future_incompatible {
202 if let Some(edition) = reason.edition() {
203 self.lint_groups
204 .entry(edition.lint_name())
205 .or_insert(LintGroup {
206 lint_ids: vec![],
207 is_externally_loaded: lint.is_externally_loaded,
208 depr: None,
209 })
210 .lint_ids
211 .push(id);
212 } else {
213 self.lint_groups
217 .entry("future_incompatible")
218 .or_insert(LintGroup {
219 lint_ids: vec![],
220 is_externally_loaded: lint.is_externally_loaded,
221 depr: None,
222 })
223 .lint_ids
224 .push(id);
225 }
226 }
227 }
228 }
229
230 fn insert_group(&mut self, name: &'static str, group: LintGroup) {
231 let previous = self.lint_groups.insert(name, group);
232 if previous.is_some() {
233 bug!("group {name:?} already exists");
234 }
235 }
236
237 pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) {
238 let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else {
239 bug!("group alias {alias:?} points to unregistered group {group_name:?}")
240 };
241
242 self.insert_group(
243 alias,
244 LintGroup {
245 lint_ids: lint_ids.clone(),
246 is_externally_loaded: false,
247 depr: Some(LintAlias { name: group_name, silent: true }),
248 },
249 );
250 }
251
252 pub fn register_group(
253 &mut self,
254 is_externally_loaded: bool,
255 name: &'static str,
256 deprecated_name: Option<&'static str>,
257 to: Vec<LintId>,
258 ) {
259 if let Some(deprecated) = deprecated_name {
260 self.insert_group(
261 deprecated,
262 LintGroup {
263 lint_ids: to.clone(),
264 is_externally_loaded,
265 depr: Some(LintAlias { name, silent: false }),
266 },
267 );
268 }
269 self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None });
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, lint_name: &str) -> Option<&[LintId]> {
296 match self.by_name.get(lint_name) {
297 Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
298 Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)),
299 Some(Removed(_)) => None,
300 Some(Ignored) => Some(&[]),
301 None => match self.lint_groups.get(lint_name) {
302 Some(LintGroup { lint_ids, .. }) => Some(lint_ids),
303 None => None,
304 },
305 }
306 }
307
308 pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
310 debug!(
311 "is_lint_group(lint_name={:?}, lint_groups={:?})",
312 lint_name,
313 self.lint_groups.keys().collect::<Vec<_>>()
314 );
315 let lint_name_str = lint_name.as_str();
316 self.lint_groups.contains_key(lint_name_str) || {
317 let warnings_name_str = crate::WARNINGS.name_lower();
318 lint_name_str == warnings_name_str
319 }
320 }
321
322 pub fn check_lint_name(
330 &self,
331 lint_name: &str,
332 tool_name: Option<Symbol>,
333 registered_tools: &RegisteredTools,
334 ) -> CheckLintNameResult<'_> {
335 if let Some(tool_name) = tool_name {
336 if tool_name != sym::rustc
338 && tool_name != sym::rustdoc
339 && !registered_tools.contains(&Ident::with_dummy_span(tool_name))
340 {
341 return CheckLintNameResult::NoTool;
342 }
343 }
344
345 let complete_name = if let Some(tool_name) = tool_name {
346 format!("{tool_name}::{lint_name}")
347 } else {
348 lint_name.to_string()
349 };
350 if let Some(tool_name) = tool_name {
352 match self.by_name.get(&complete_name) {
353 None => match self.lint_groups.get(&*complete_name) {
354 None => {
356 debug!("lints={:?}", self.by_name);
359 let tool_prefix = format!("{tool_name}::");
360
361 return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
362 self.no_lint_suggestion(&complete_name, tool_name.as_str())
363 } else {
364 CheckLintNameResult::MissingTool
367 };
368 }
369 Some(LintGroup { lint_ids, depr, .. }) => {
370 return if let &Some(LintAlias { name, silent: false }) = depr {
371 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
372 } else {
373 CheckLintNameResult::Tool(lint_ids, None)
374 };
375 }
376 },
377 Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
378 _ => {}
381 }
382 }
383 match self.by_name.get(&complete_name) {
384 Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
385 Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
386 None => match self.lint_groups.get(&*complete_name) {
387 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
390 Some(LintGroup { lint_ids, depr, .. }) => {
391 if let &Some(LintAlias { name, silent: false }) = depr {
393 CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
394 } else {
395 CheckLintNameResult::Ok(lint_ids)
396 }
397 }
398 },
399 Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
400 Some(&Ignored) => CheckLintNameResult::Ok(&[]),
401 }
402 }
403
404 fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
405 let name_lower = lint_name.to_lowercase();
406
407 if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() {
408 return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
410 }
411
412 #[allow(rustc::potential_query_instability)]
418 let mut groups: Vec<_> = self
419 .lint_groups
420 .iter()
421 .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k))
422 .collect();
423 groups.sort();
424 let groups = groups.iter().map(|k| Symbol::intern(k));
425 let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
426 let names: Vec<Symbol> = groups.chain(lints).collect();
427 let mut lookups = vec![Symbol::intern(&name_lower)];
428 if let Some(stripped) = name_lower.split("::").last() {
429 lookups.push(Symbol::intern(stripped));
430 }
431 let res = find_best_match_for_names(&names, &lookups, None);
432 let is_rustc = res.map_or_else(
433 || false,
434 |s| name_lower.contains("::") && !s.as_str().starts_with(tool_name),
435 );
436 let suggestion = res.map(|s| (s, is_rustc));
437 CheckLintNameResult::NoLint(suggestion)
438 }
439
440 fn check_tool_name_for_backwards_compat(
441 &self,
442 lint_name: &str,
443 tool_name: &str,
444 ) -> CheckLintNameResult<'_> {
445 let complete_name = format!("{tool_name}::{lint_name}");
446 match self.by_name.get(&complete_name) {
447 None => match self.lint_groups.get(&*complete_name) {
448 None => self.no_lint_suggestion(lint_name, tool_name),
450 Some(LintGroup { lint_ids, .. }) => {
451 CheckLintNameResult::Tool(lint_ids, Some(complete_name))
452 }
453 },
454 Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)),
455 Some(other) => {
456 debug!("got renamed lint {:?}", other);
457 CheckLintNameResult::NoLint(None)
458 }
459 }
460 }
461}
462
463pub struct LateContext<'tcx> {
465 pub tcx: TyCtxt<'tcx>,
467
468 pub enclosing_body: Option<hir::BodyId>,
470
471 pub(super) cached_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
476
477 pub param_env: ty::ParamEnv<'tcx>,
479
480 pub effective_visibilities: &'tcx EffectiveVisibilities,
482
483 pub last_node_with_lint_attrs: hir::HirId,
484
485 pub generics: Option<&'tcx hir::Generics<'tcx>>,
487
488 pub only_module: bool,
490}
491
492pub struct EarlyContext<'a> {
494 pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>,
495 pub buffered: LintBuffer,
496}
497
498pub trait LintContext {
499 fn sess(&self) -> &Session;
500
501 #[rustc_lint_diagnostics]
507 #[track_caller]
508 fn opt_span_lint<S: Into<MultiSpan>>(
509 &self,
510 lint: &'static Lint,
511 span: Option<S>,
512 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
513 );
514
515 fn emit_span_lint<S: Into<MultiSpan>>(
518 &self,
519 lint: &'static Lint,
520 span: S,
521 decorator: impl for<'a> LintDiagnostic<'a, ()>,
522 ) {
523 self.opt_span_lint(lint, Some(span), |lint| {
524 decorator.decorate_lint(lint);
525 });
526 }
527
528 fn emit_span_lint_lazy<S: Into<MultiSpan>, L: for<'a> LintDiagnostic<'a, ()>>(
531 &self,
532 lint: &'static Lint,
533 span: S,
534 decorator: impl FnOnce() -> L,
535 ) {
536 self.opt_span_lint(lint, Some(span), |lint| {
537 let decorator = decorator();
538 decorator.decorate_lint(lint);
539 });
540 }
541
542 #[rustc_lint_diagnostics]
546 #[track_caller]
547 fn span_lint<S: Into<MultiSpan>>(
548 &self,
549 lint: &'static Lint,
550 span: S,
551 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
552 ) {
553 self.opt_span_lint(lint, Some(span), decorate);
554 }
555
556 fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> LintDiagnostic<'a, ()>) {
559 self.opt_span_lint(lint, None as Option<Span>, |lint| {
560 decorator.decorate_lint(lint);
561 });
562 }
563
564 #[rustc_lint_diagnostics]
568 fn lint(&self, lint: &'static Lint, decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>)) {
569 self.opt_span_lint(lint, None as Option<Span>, decorate);
570 }
571
572 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource;
574
575 fn fulfill_expectation(&self, expectation: LintExpectationId) {
583 #[allow(rustc::diagnostic_outside_of_impl)]
588 #[allow(rustc::untranslatable_diagnostic)]
589 self.sess()
590 .dcx()
591 .struct_expect(
592 "this is a dummy diagnostic, to submit and store an expectation",
593 expectation,
594 )
595 .emit();
596 }
597}
598
599impl<'a> EarlyContext<'a> {
600 pub(crate) fn new(
601 sess: &'a Session,
602 features: &'a Features,
603 lint_added_lints: bool,
604 lint_store: &'a LintStore,
605 registered_tools: &'a RegisteredTools,
606 buffered: LintBuffer,
607 ) -> EarlyContext<'a> {
608 EarlyContext {
609 builder: LintLevelsBuilder::new(
610 sess,
611 features,
612 lint_added_lints,
613 lint_store,
614 registered_tools,
615 ),
616 buffered,
617 }
618 }
619}
620
621impl<'tcx> LintContext for LateContext<'tcx> {
622 fn sess(&self) -> &Session {
624 self.tcx.sess
625 }
626
627 #[rustc_lint_diagnostics]
628 fn opt_span_lint<S: Into<MultiSpan>>(
629 &self,
630 lint: &'static Lint,
631 span: Option<S>,
632 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
633 ) {
634 let hir_id = self.last_node_with_lint_attrs;
635
636 match span {
637 Some(s) => self.tcx.node_span_lint(lint, hir_id, s, decorate),
638 None => self.tcx.node_lint(lint, hir_id, decorate),
639 }
640 }
641
642 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
643 self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs)
644 }
645}
646
647impl LintContext for EarlyContext<'_> {
648 fn sess(&self) -> &Session {
650 self.builder.sess()
651 }
652
653 #[rustc_lint_diagnostics]
654 fn opt_span_lint<S: Into<MultiSpan>>(
655 &self,
656 lint: &'static Lint,
657 span: Option<S>,
658 decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
659 ) {
660 self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorate)
661 }
662
663 fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
664 self.builder.lint_level(lint)
665 }
666}
667
668impl<'tcx> LateContext<'tcx> {
669 pub fn typing_mode(&self) -> TypingMode<'tcx> {
672 TypingMode::non_body_analysis()
675 }
676
677 pub fn typing_env(&self) -> TypingEnv<'tcx> {
678 TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
679 }
680
681 pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
682 self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
683 }
684
685 pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
686 self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
687 }
688
689 pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
692 self.cached_typeck_results.get().or_else(|| {
693 self.enclosing_body.map(|body| {
694 let typeck_results = self.tcx.typeck_body(body);
695 self.cached_typeck_results.set(Some(typeck_results));
696 typeck_results
697 })
698 })
699 }
700
701 #[track_caller]
705 pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
706 self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body")
707 }
708
709 pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
713 match *qpath {
714 hir::QPath::Resolved(_, path) => path.res,
715 hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
716 .maybe_typeck_results()
717 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
718 .or_else(|| {
719 self.tcx
720 .has_typeck_results(id.owner.def_id)
721 .then(|| self.tcx.typeck(id.owner.def_id))
722 })
723 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
724 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
725 }
726 }
727
728 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
748 struct AbsolutePathPrinter<'tcx> {
749 tcx: TyCtxt<'tcx>,
750 path: Vec<Symbol>,
751 }
752
753 impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
754 fn tcx(&self) -> TyCtxt<'tcx> {
755 self.tcx
756 }
757
758 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
759 Ok(())
760 }
761
762 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
763 Ok(())
764 }
765
766 fn print_dyn_existential(
767 &mut self,
768 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
769 ) -> Result<(), PrintError> {
770 Ok(())
771 }
772
773 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
774 Ok(())
775 }
776
777 fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
778 self.path = vec![self.tcx.crate_name(cnum)];
779 Ok(())
780 }
781
782 fn path_qualified(
783 &mut self,
784 self_ty: Ty<'tcx>,
785 trait_ref: Option<ty::TraitRef<'tcx>>,
786 ) -> Result<(), PrintError> {
787 if trait_ref.is_none() {
788 if let ty::Adt(def, args) = self_ty.kind() {
789 return self.print_def_path(def.did(), args);
790 }
791 }
792
793 with_no_trimmed_paths!({
795 self.path = vec![match trait_ref {
796 Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
797 None => Symbol::intern(&format!("<{self_ty}>")),
798 }];
799 Ok(())
800 })
801 }
802
803 fn path_append_impl(
804 &mut self,
805 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
806 _disambiguated_data: &DisambiguatedDefPathData,
807 self_ty: Ty<'tcx>,
808 trait_ref: Option<ty::TraitRef<'tcx>>,
809 ) -> Result<(), PrintError> {
810 print_prefix(self)?;
811
812 self.path.push(match trait_ref {
814 Some(trait_ref) => {
815 with_no_trimmed_paths!(Symbol::intern(&format!(
816 "<impl {} for {}>",
817 trait_ref.print_only_trait_path(),
818 self_ty
819 )))
820 }
821 None => {
822 with_no_trimmed_paths!(Symbol::intern(&format!("<impl {self_ty}>")))
823 }
824 });
825
826 Ok(())
827 }
828
829 fn path_append(
830 &mut self,
831 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
832 disambiguated_data: &DisambiguatedDefPathData,
833 ) -> Result<(), PrintError> {
834 print_prefix(self)?;
835
836 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
838 return Ok(());
839 }
840
841 self.path.push(match disambiguated_data.data.get_opt_name() {
842 Some(sym) => sym,
843 None => Symbol::intern(&disambiguated_data.data.to_string()),
844 });
845 Ok(())
846 }
847
848 fn path_generic_args(
849 &mut self,
850 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
851 _args: &[GenericArg<'tcx>],
852 ) -> Result<(), PrintError> {
853 print_prefix(self)
854 }
855 }
856
857 let mut printer = AbsolutePathPrinter { tcx: self.tcx, path: vec![] };
858 printer.print_def_path(def_id, &[]).unwrap();
859 printer.path
860 }
861
862 pub fn get_associated_type(
865 &self,
866 self_ty: Ty<'tcx>,
867 trait_id: DefId,
868 name: Symbol,
869 ) -> Option<Ty<'tcx>> {
870 let tcx = self.tcx;
871 tcx.associated_items(trait_id)
872 .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
873 .and_then(|assoc| {
874 let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
875 tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()
876 })
877 }
878
879 pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
883 let has_attr = |id: hir::HirId| -> bool {
884 for attr in self.tcx.hir_attrs(id) {
885 if attr.span().desugaring_kind().is_none() {
886 return true;
887 }
888 }
889 false
890 };
891 expr.precedence(&has_attr)
892 }
893
894 pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
910 expr = expr.peel_blocks();
911
912 while let hir::ExprKind::Path(ref qpath) = expr.kind
913 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
914 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
915 _ => None,
916 }
917 && let Some(init) = match parent_node {
918 hir::Node::Expr(expr) => Some(expr),
919 hir::Node::LetStmt(hir::LetStmt {
920 init,
921 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
923 ..
924 }) => *init,
925 _ => None,
926 }
927 {
928 expr = init.peel_blocks();
929 }
930 expr
931 }
932
933 pub fn expr_or_init_with_outside_body<'a>(
956 &self,
957 mut expr: &'a hir::Expr<'tcx>,
958 ) -> &'a hir::Expr<'tcx> {
959 expr = expr.peel_blocks();
960
961 while let hir::ExprKind::Path(ref qpath) = expr.kind
962 && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
963 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
964 Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
965 _ => None,
966 }
967 && let Some(init) = match parent_node {
968 hir::Node::Expr(expr) => Some(expr),
969 hir::Node::LetStmt(hir::LetStmt {
970 init,
971 pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
973 ..
974 }) => *init,
975 hir::Node::Item(item) => match item.kind {
976 hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
977 Some(self.tcx.hir_body(body_id).value)
978 }
979 _ => None,
980 },
981 _ => None,
982 }
983 {
984 expr = init.peel_blocks();
985 }
986 expr
987 }
988}
989
990impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
991 #[inline]
992 fn data_layout(&self) -> &abi::TargetDataLayout {
993 &self.tcx.data_layout
994 }
995}
996
997impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
998 #[inline]
999 fn tcx(&self) -> TyCtxt<'tcx> {
1000 self.tcx
1001 }
1002}
1003
1004impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
1005 #[inline]
1006 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
1007 self.typing_env()
1008 }
1009}
1010
1011impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
1012 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
1013
1014 #[inline]
1015 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
1016 err
1017 }
1018}