1use rustc_hir::def::{DefKind, Res};
2use rustc_hir::def_id::DefId;
3use rustc_hir::{
4 self as hir, Expr, ExprKind, HirId, LangItem, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, TyKind,
5};
6use rustc_lint::LateContext;
7use rustc_middle::ty::layout::HasTyCtxt;
8use rustc_middle::ty::{AdtDef, AdtKind, Binder, EarlyBinder, Ty, TypeckResults};
9use rustc_span::{Ident, Symbol};
10
11pub trait HasHirId: Copy {
13 fn hir_id(self) -> HirId;
14}
15impl HasHirId for HirId {
16 #[inline]
17 fn hir_id(self) -> HirId {
18 self
19 }
20}
21impl HasHirId for &Expr<'_> {
22 #[inline]
23 fn hir_id(self) -> HirId {
24 self.hir_id
25 }
26}
27
28type DefRes = (DefKind, DefId);
29
30pub trait MaybeTypeckRes<'tcx> {
31 fn typeck_res(&self) -> Option<&TypeckResults<'tcx>>;
37
38 #[inline]
44 #[cfg_attr(debug_assertions, track_caller)]
45 fn ty_based_def(&self, node: impl HasHirId) -> Option<DefRes> {
46 #[inline]
47 #[cfg_attr(debug_assertions, track_caller)]
48 fn f(typeck: &TypeckResults<'_>, id: HirId) -> Option<DefRes> {
49 if typeck.hir_owner == id.owner {
50 let def = typeck.type_dependent_def(id);
51 debug_assert!(
52 def.is_some(),
53 "attempted type-dependent lookup for a node with no definition\
54 \n node `{id:?}`",
55 );
56 def
57 } else {
58 debug_assert!(
59 false,
60 "attempted type-dependent lookup for a node in the wrong body\
61 \n in body `{:?}`\
62 \n expected body `{:?}`",
63 typeck.hir_owner, id.owner,
64 );
65 None
66 }
67 }
68 self.typeck_res().and_then(|typeck| f(typeck, node.hir_id()))
69 }
70}
71impl<'tcx> MaybeTypeckRes<'tcx> for LateContext<'tcx> {
72 #[inline]
73 #[cfg_attr(debug_assertions, track_caller)]
74 fn typeck_res(&self) -> Option<&TypeckResults<'tcx>> {
75 if let Some(typeck) = self.typeck_results {
76 Some(typeck)
77 } else {
78 debug_assert!(false, "attempted type-dependent lookup in a non-body context");
82 None
83 }
84 }
85}
86impl<'tcx> MaybeTypeckRes<'tcx> for TypeckResults<'tcx> {
87 #[inline]
88 fn typeck_res(&self) -> Option<&TypeckResults<'tcx>> {
89 Some(self)
90 }
91}
92
93type QPathId<'tcx> = (&'tcx QPath<'tcx>, HirId);
95
96pub trait MaybeQPath<'a>: Copy {
98 fn opt_qpath(self) -> Option<QPathId<'a>>;
101
102 #[inline]
104 #[cfg_attr(debug_assertions, track_caller)]
105 fn res<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> Res {
106 #[cfg_attr(debug_assertions, track_caller)]
107 fn f(qpath: &QPath<'_>, id: HirId, typeck: &TypeckResults<'_>) -> Res {
108 match *qpath {
109 QPath::Resolved(_, p) => p.res,
110 QPath::TypeRelative(..) if let Some((kind, id)) = typeck.ty_based_def(id) => Res::Def(kind, id),
111 QPath::TypeRelative(..) => Res::Err,
112 }
113 }
114 match self.opt_qpath() {
115 Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck),
116 _ => Res::Err,
117 }
118 }
119
120 #[inline]
123 #[cfg_attr(debug_assertions, track_caller)]
124 fn res_if_named<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>, name: Symbol) -> Res {
125 #[cfg_attr(debug_assertions, track_caller)]
126 fn f(qpath: &QPath<'_>, id: HirId, typeck: &TypeckResults<'_>, name: Symbol) -> Res {
127 match *qpath {
128 QPath::Resolved(_, p)
129 if let [.., seg] = p.segments
130 && seg.ident.name == name =>
131 {
132 p.res
133 },
134 QPath::TypeRelative(_, seg)
135 if seg.ident.name == name
136 && let Some((kind, id)) = typeck.ty_based_def(id) =>
137 {
138 Res::Def(kind, id)
139 },
140 QPath::Resolved(..) | QPath::TypeRelative(..) => Res::Err,
141 }
142 }
143 match self.opt_qpath() {
144 Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck, name),
145 _ => Res::Err,
146 }
147 }
148
149 #[inline]
151 #[cfg_attr(debug_assertions, track_caller)]
152 fn res_with_seg<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> (Res, Option<&'a PathSegment<'a>>) {
153 #[cfg_attr(debug_assertions, track_caller)]
154 fn f<'a>(qpath: &QPath<'a>, id: HirId, typeck: &TypeckResults<'_>) -> (Res, Option<&'a PathSegment<'a>>) {
155 match *qpath {
156 QPath::Resolved(_, p) if let [.., seg] = p.segments => (p.res, Some(seg)),
157 QPath::TypeRelative(_, seg) if let Some((kind, id)) = typeck.ty_based_def(id) => {
158 (Res::Def(kind, id), Some(seg))
159 },
160 QPath::Resolved(..) | QPath::TypeRelative(..) => (Res::Err, None),
161 }
162 }
163 match self.opt_qpath() {
164 Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck),
165 _ => (Res::Err, None),
166 }
167 }
168
169 #[inline]
174 #[cfg_attr(debug_assertions, track_caller)]
175 fn typeless_res<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> Res {
176 #[cfg_attr(debug_assertions, track_caller)]
177 fn f(qpath: &QPath<'_>, id: HirId, typeck: &TypeckResults<'_>) -> Res {
178 match *qpath {
179 QPath::Resolved(
180 None
181 | Some(&hir::Ty {
182 kind: TyKind::Infer(()),
183 ..
184 }),
185 p,
186 ) => p.res,
187 QPath::TypeRelative(
188 &hir::Ty {
189 kind: TyKind::Infer(()),
190 ..
191 },
192 _,
193 ) if let Some((kind, id)) = typeck.ty_based_def(id) => Res::Def(kind, id),
194 QPath::Resolved(..) | QPath::TypeRelative(..) => Res::Err,
195 }
196 }
197 match self.opt_qpath() {
198 Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck),
199 _ => Res::Err,
200 }
201 }
202
203 #[inline]
208 #[cfg_attr(debug_assertions, track_caller)]
209 fn typeless_res_if_named<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>, name: Symbol) -> Res {
210 #[cfg_attr(debug_assertions, track_caller)]
211 fn f(qpath: &QPath<'_>, id: HirId, typeck: &TypeckResults<'_>, name: Symbol) -> Res {
212 match *qpath {
213 QPath::Resolved(
214 None
215 | Some(&hir::Ty {
216 kind: TyKind::Infer(()),
217 ..
218 }),
219 p,
220 ) if let [.., seg] = p.segments
221 && seg.ident.name == name =>
222 {
223 p.res
224 },
225 QPath::TypeRelative(
226 &hir::Ty {
227 kind: TyKind::Infer(()),
228 ..
229 },
230 seg,
231 ) if seg.ident.name == name
232 && let Some((kind, id)) = typeck.ty_based_def(id) =>
233 {
234 Res::Def(kind, id)
235 },
236 QPath::Resolved(..) | QPath::TypeRelative(..) => Res::Err,
237 }
238 }
239 match self.opt_qpath() {
240 Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck, name),
241 _ => Res::Err,
242 }
243 }
244
245 #[inline]
249 #[cfg_attr(debug_assertions, track_caller)]
250 fn ty_rel_def<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> Option<DefRes> {
251 match self.opt_qpath() {
252 Some((QPath::TypeRelative(..), id)) => typeck.ty_based_def(id),
253 _ => None,
254 }
255 }
256
257 #[inline]
262 #[cfg_attr(debug_assertions, track_caller)]
263 fn ty_rel_def_if_named<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>, name: Symbol) -> Option<DefRes> {
264 match self.opt_qpath() {
265 Some((&QPath::TypeRelative(_, seg), id)) if seg.ident.name == name => typeck.ty_based_def(id),
266 _ => None,
267 }
268 }
269
270 #[inline]
275 #[cfg_attr(debug_assertions, track_caller)]
276 fn ty_rel_def_with_seg<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> Option<(DefRes, &'a PathSegment<'a>)> {
277 match self.opt_qpath() {
278 Some((QPath::TypeRelative(_, seg), id)) if let Some(def) = typeck.ty_based_def(id) => Some((def, seg)),
279 _ => None,
280 }
281 }
282}
283
284impl<'tcx> MaybeQPath<'tcx> for QPathId<'tcx> {
285 #[inline]
286 fn opt_qpath(self) -> Option<QPathId<'tcx>> {
287 Some((self.0, self.1))
288 }
289}
290impl<'tcx> MaybeQPath<'tcx> for &'tcx Expr<'_> {
291 #[inline]
292 fn opt_qpath(self) -> Option<QPathId<'tcx>> {
293 match &self.kind {
294 ExprKind::Path(qpath) => Some((qpath, self.hir_id)),
295 _ => None,
296 }
297 }
298}
299impl<'tcx> MaybeQPath<'tcx> for &'tcx PatExpr<'_> {
300 #[inline]
301 fn opt_qpath(self) -> Option<QPathId<'tcx>> {
302 match &self.kind {
303 PatExprKind::Path(qpath) => Some((qpath, self.hir_id)),
304 PatExprKind::Lit { .. } => None,
305 }
306 }
307}
308impl<'tcx, AmbigArg> MaybeQPath<'tcx> for &'tcx hir::Ty<'_, AmbigArg> {
309 #[inline]
310 fn opt_qpath(self) -> Option<QPathId<'tcx>> {
311 match &self.kind {
312 TyKind::Path(qpath) => Some((qpath, self.hir_id)),
313 _ => None,
314 }
315 }
316}
317impl<'tcx> MaybeQPath<'tcx> for &'_ Pat<'tcx> {
318 #[inline]
319 fn opt_qpath(self) -> Option<QPathId<'tcx>> {
320 match self.kind {
321 PatKind::Expr(e) => e.opt_qpath(),
322 _ => None,
323 }
324 }
325}
326impl<'tcx, T: MaybeQPath<'tcx>> MaybeQPath<'tcx> for Option<T> {
327 #[inline]
328 fn opt_qpath(self) -> Option<QPathId<'tcx>> {
329 self.and_then(T::opt_qpath)
330 }
331}
332impl<'tcx, T: Copy + MaybeQPath<'tcx>> MaybeQPath<'tcx> for &Option<T> {
333 #[inline]
334 fn opt_qpath(self) -> Option<QPathId<'tcx>> {
335 self.and_then(T::opt_qpath)
336 }
337}
338
339type OptResPath<'tcx> = (Option<&'tcx hir::Ty<'tcx>>, Option<&'tcx Path<'tcx>>);
341
342type OptTyRelPath<'tcx> = Option<(&'tcx hir::Ty<'tcx>, &'tcx PathSegment<'tcx>)>;
343
344pub trait MaybeResPath<'a>: Copy {
355 fn opt_res_path(self) -> OptResPath<'a>;
358
359 fn opt_ty_rel_path(self) -> OptTyRelPath<'a>;
362
363 #[inline]
366 fn basic_res(self) -> &'a Res {
367 self.opt_res_path().1.map_or(&Res::Err, |p| &p.res)
368 }
369
370 #[inline]
372 fn res_local_id(self) -> Option<HirId> {
373 if let (_, Some(p)) = self.opt_res_path()
374 && let Res::Local(id) = p.res
375 {
376 Some(id)
377 } else {
378 None
379 }
380 }
381
382 fn res_local_id_and_ident(self) -> Option<(HirId, &'a Ident)> {
384 if let (_, Some(p)) = self.opt_res_path()
385 && let Res::Local(id) = p.res
386 && let [seg] = p.segments
387 {
388 Some((id, &seg.ident))
389 } else {
390 None
391 }
392 }
393}
394impl<'a> MaybeResPath<'a> for &'a Path<'a> {
395 #[inline]
396 fn opt_res_path(self) -> OptResPath<'a> {
397 (None, Some(self))
398 }
399
400 #[inline]
401 fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
402 None
403 }
404
405 #[inline]
406 fn basic_res(self) -> &'a Res {
407 &self.res
408 }
409}
410impl<'a> MaybeResPath<'a> for &QPath<'a> {
411 #[inline]
412 fn opt_res_path(self) -> OptResPath<'a> {
413 match *self {
414 QPath::Resolved(ty, path) => (ty, Some(path)),
415 QPath::TypeRelative(..) => (None, None),
416 }
417 }
418
419 #[inline]
420 fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
421 match *self {
422 QPath::TypeRelative(ty, seg) => Some((ty, seg)),
423 QPath::Resolved(..) => None,
424 }
425 }
426}
427impl<'a> MaybeResPath<'a> for &Expr<'a> {
428 #[inline]
429 fn opt_res_path(self) -> OptResPath<'a> {
430 match &self.kind {
431 ExprKind::Path(qpath) => qpath.opt_res_path(),
432 _ => (None, None),
433 }
434 }
435
436 #[inline]
437 fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
438 match &self.kind {
439 ExprKind::Path(qpath) => qpath.opt_ty_rel_path(),
440 _ => None,
441 }
442 }
443}
444impl<'a> MaybeResPath<'a> for &PatExpr<'a> {
445 #[inline]
446 fn opt_res_path(self) -> OptResPath<'a> {
447 match &self.kind {
448 PatExprKind::Path(qpath) => qpath.opt_res_path(),
449 PatExprKind::Lit { .. } => (None, None),
450 }
451 }
452
453 #[inline]
454 fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
455 match &self.kind {
456 PatExprKind::Path(qpath) => qpath.opt_ty_rel_path(),
457 PatExprKind::Lit { .. } => None,
458 }
459 }
460}
461impl<'a, AmbigArg> MaybeResPath<'a> for &hir::Ty<'a, AmbigArg> {
462 #[inline]
463 fn opt_res_path(self) -> OptResPath<'a> {
464 match &self.kind {
465 TyKind::Path(qpath) => qpath.opt_res_path(),
466 _ => (None, None),
467 }
468 }
469
470 #[inline]
471 fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
472 match &self.kind {
473 TyKind::Path(qpath) => qpath.opt_ty_rel_path(),
474 _ => None,
475 }
476 }
477}
478impl<'a> MaybeResPath<'a> for &Pat<'a> {
479 #[inline]
480 fn opt_res_path(self) -> OptResPath<'a> {
481 match self.kind {
482 PatKind::Expr(e) => e.opt_res_path(),
483 _ => (None, None),
484 }
485 }
486
487 #[inline]
488 fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
489 match self.kind {
490 PatKind::Expr(e) => e.opt_ty_rel_path(),
491 _ => None,
492 }
493 }
494}
495impl<'a, T: MaybeResPath<'a>> MaybeResPath<'a> for Option<T> {
496 #[inline]
497 fn opt_res_path(self) -> OptResPath<'a> {
498 match self {
499 Some(x) => T::opt_res_path(x),
500 None => (None, None),
501 }
502 }
503
504 #[inline]
505 fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
506 self.and_then(T::opt_ty_rel_path)
507 }
508
509 #[inline]
510 fn basic_res(self) -> &'a Res {
511 self.map_or(&Res::Err, T::basic_res)
512 }
513}
514
515pub trait MaybeDef: Copy {
517 fn opt_def_id(self) -> Option<DefId>;
518
519 fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)>;
522
523 #[inline]
525 fn opt_diag_name<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<Symbol> {
526 self.opt_def_id().and_then(|id| tcx.tcx().get_diagnostic_name(id))
527 }
528
529 #[inline]
531 fn is_diag_item<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>, name: Symbol) -> bool {
532 self.opt_def_id()
533 .is_some_and(|id| tcx.tcx().is_diagnostic_item(name, id))
534 }
535
536 #[inline]
538 fn is_lang_item<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>, item: LangItem) -> bool {
539 self.opt_def_id()
540 .is_some_and(|id| tcx.tcx().lang_items().get(item) == Some(id))
541 }
542
543 #[inline]
545 fn opt_impl_ty<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<EarlyBinder<'tcx, Ty<'tcx>>> {
546 match self.opt_def(tcx) {
547 Some((DefKind::Impl { .. }, id)) => Some(tcx.tcx().type_of(id)),
548 _ => None,
549 }
550 }
551
552 #[inline]
554 fn opt_parent<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<DefId> {
555 self.opt_def_id().and_then(|id| tcx.tcx().opt_parent(id))
556 }
557
558 #[inline]
560 fn is_impl<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> bool {
561 matches!(self.opt_def(tcx), Some((DefKind::Impl { .. }, _)))
562 }
563
564 #[inline]
566 fn ctor_parent<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<DefId> {
567 match self.opt_def(tcx) {
568 Some((DefKind::Ctor(..), id)) => tcx.tcx().opt_parent(id),
569 _ => None,
570 }
571 }
572
573 #[inline]
576 fn assoc_parent<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<DefId> {
577 match self.opt_def(tcx) {
578 Some((DefKind::AssocConst { .. } | DefKind::AssocFn | DefKind::AssocTy, id)) => tcx.tcx().opt_parent(id),
579 _ => None,
580 }
581 }
582
583 #[inline]
586 fn assoc_fn_parent<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<DefId> {
587 match self.opt_def(tcx) {
588 Some((DefKind::AssocFn, id)) => tcx.tcx().opt_parent(id),
589 _ => None,
590 }
591 }
592}
593impl MaybeDef for DefId {
594 #[inline]
595 fn opt_def_id(self) -> Option<DefId> {
596 Some(self)
597 }
598
599 #[inline]
600 fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
601 self.opt_def_id().map(|id| (tcx.tcx().def_kind(id), id))
602 }
603}
604impl MaybeDef for (DefKind, DefId) {
605 #[inline]
606 fn opt_def_id(self) -> Option<DefId> {
607 Some(self.1)
608 }
609
610 #[inline]
611 fn opt_def<'tcx>(self, _: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
612 Some(self)
613 }
614}
615impl MaybeDef for AdtDef<'_> {
616 #[inline]
617 fn opt_def_id(self) -> Option<DefId> {
618 Some(self.did())
619 }
620
621 #[inline]
622 fn opt_def<'tcx>(self, _: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
623 let did = self.did();
624 match self.adt_kind() {
625 AdtKind::Enum => Some((DefKind::Enum, did)),
626 AdtKind::Struct => Some((DefKind::Struct, did)),
627 AdtKind::Union => Some((DefKind::Union, did)),
628 }
629 }
630}
631impl MaybeDef for Ty<'_> {
632 #[inline]
633 fn opt_def_id(self) -> Option<DefId> {
634 self.ty_adt_def().opt_def_id()
635 }
636
637 #[inline]
638 fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
639 self.ty_adt_def().opt_def(tcx)
640 }
641}
642impl MaybeDef for Res {
643 #[inline]
644 fn opt_def_id(self) -> Option<DefId> {
645 Res::opt_def_id(&self)
646 }
647
648 #[inline]
649 fn opt_def<'tcx>(self, _: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
650 match self {
651 Res::Def(kind, id) => Some((kind, id)),
652 _ => None,
653 }
654 }
655}
656impl<T: MaybeDef> MaybeDef for Option<T> {
657 #[inline]
658 fn opt_def_id(self) -> Option<DefId> {
659 self.and_then(T::opt_def_id)
660 }
661
662 #[inline]
663 fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
664 self.and_then(|x| T::opt_def(x, tcx))
665 }
666}
667impl<T: MaybeDef> MaybeDef for EarlyBinder<'_, T> {
668 #[inline]
669 fn opt_def_id(self) -> Option<DefId> {
670 self.skip_binder().opt_def_id()
671 }
672
673 #[inline]
674 fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
675 self.skip_binder().opt_def(tcx)
676 }
677}
678impl<T: MaybeDef> MaybeDef for Binder<'_, T> {
679 #[inline]
680 fn opt_def_id(self) -> Option<DefId> {
681 self.skip_binder().opt_def_id()
682 }
683
684 #[inline]
685 fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
686 self.skip_binder().opt_def(tcx)
687 }
688}