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