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