1 //! This module provides a simplified abstraction for working with
2 //! code blocks identified by their integer `NodeId`. In particular,
3 //! it captures a common set of attributes that all "function-like
4 //! things" (represented by `FnLike` instances) share. For example,
5 //! all `FnLike` instances have a type signature (be it explicit or
6 //! inferred). And all `FnLike` instances have a body, i.e., the code
7 //! that is run when the function-like thing it represents is invoked.
9 //! With the above abstraction in place, one can treat the program
10 //! text as a collection of blocks of code (and most such blocks are
11 //! nested within a uniquely determined `FnLike`), and users can ask
12 //! for the `Code` associated with a particular NodeId.
14 use crate::hir
::map
::Map
;
15 use rustc_ast
::ast
::{Attribute, Ident}
;
17 use rustc_hir
::intravisit
::FnKind
;
18 use rustc_hir
::{Expr, FnDecl, Node}
;
21 /// An FnLikeNode is a Node that is like a fn, in that it has a decl
22 /// and a body (as well as a NodeId, a span, etc).
24 /// More specifically, it is one of either:
26 /// - A function item,
27 /// - A closure expr (i.e., an ExprKind::Closure), or
28 /// - The default implementation for a trait method.
30 /// To construct one, use the `Code::from_node` function.
31 #[derive(Copy, Clone, Debug)]
32 pub struct FnLikeNode
<'a
> {
36 /// MaybeFnLike wraps a method that indicates if an object
37 /// corresponds to some FnLikeNode.
39 fn is_fn_like(&self) -> bool
;
42 impl MaybeFnLike
for hir
::Item
<'_
> {
43 fn is_fn_like(&self) -> bool
{
45 hir
::ItemKind
::Fn(..) => true,
51 impl MaybeFnLike
for hir
::ImplItem
<'_
> {
52 fn is_fn_like(&self) -> bool
{
54 hir
::ImplItemKind
::Method(..) => true,
60 impl MaybeFnLike
for hir
::TraitItem
<'_
> {
61 fn is_fn_like(&self) -> bool
{
63 hir
::TraitItemKind
::Method(_
, hir
::TraitMethod
::Provided(_
)) => true,
69 impl MaybeFnLike
for hir
::Expr
<'_
> {
70 fn is_fn_like(&self) -> bool
{
72 hir
::ExprKind
::Closure(..) => true,
78 /// Carries either an FnLikeNode or a Expr, as these are the two
79 /// constructs that correspond to "code" (as in, something from which
80 /// we can construct a control-flow graph).
81 #[derive(Copy, Clone)]
83 FnLike(FnLikeNode
<'a
>),
88 pub fn id(&self) -> hir
::HirId
{
90 Code
::FnLike(node
) => node
.id(),
91 Code
::Expr(block
) => block
.hir_id
,
95 /// Attempts to construct a Code from presumed FnLike or Expr node input.
96 pub fn from_node(map
: &Map
<'a
>, id
: hir
::HirId
) -> Option
<Code
<'a
>> {
99 // Use the parent, hopefully an expression node.
100 Code
::from_node(map
, map
.get_parent_node(id
))
102 Node
::Expr(expr
) => Some(Code
::Expr(expr
)),
103 node
=> FnLikeNode
::from_node(node
).map(Code
::FnLike
),
108 /// These are all the components one can extract from a fn item for
109 /// use when implementing FnLikeNode operations.
110 struct ItemFnParts
<'a
> {
112 decl
: &'a hir
::FnDecl
<'a
>,
113 header
: hir
::FnHeader
,
114 vis
: &'a hir
::Visibility
<'a
>,
115 generics
: &'a hir
::Generics
<'a
>,
119 attrs
: &'a
[Attribute
],
122 /// These are all the components one can extract from a closure expr
123 /// for use when implementing FnLikeNode operations.
124 struct ClosureParts
<'a
> {
125 decl
: &'a FnDecl
<'a
>,
129 attrs
: &'a
[Attribute
],
132 impl<'a
> ClosureParts
<'a
> {
138 attrs
: &'a
[Attribute
],
140 ClosureParts { decl: d, body: b, id, span: s, attrs }
144 impl<'a
> FnLikeNode
<'a
> {
145 /// Attempts to construct a FnLikeNode from presumed FnLike node input.
146 pub fn from_node(node
: Node
<'_
>) -> Option
<FnLikeNode
<'_
>> {
147 let fn_like
= match node
{
148 Node
::Item(item
) => item
.is_fn_like(),
149 Node
::TraitItem(tm
) => tm
.is_fn_like(),
150 Node
::ImplItem(it
) => it
.is_fn_like(),
151 Node
::Expr(e
) => e
.is_fn_like(),
154 fn_like
.then_some(FnLikeNode { node }
)
157 pub fn body(self) -> hir
::BodyId
{
159 |i
: ItemFnParts
<'a
>| i
.body
,
160 |_
, _
, _
: &'a hir
::FnSig
<'a
>, _
, body
: hir
::BodyId
, _
, _
| body
,
161 |c
: ClosureParts
<'a
>| c
.body
,
165 pub fn decl(self) -> &'a FnDecl
<'a
> {
167 |i
: ItemFnParts
<'a
>| &*i
.decl
,
168 |_
, _
, sig
: &'a hir
::FnSig
<'a
>, _
, _
, _
, _
| &sig
.decl
,
169 |c
: ClosureParts
<'a
>| c
.decl
,
173 pub fn span(self) -> Span
{
175 |i
: ItemFnParts
<'_
>| i
.span
,
176 |_
, _
, _
: &'a hir
::FnSig
<'a
>, _
, _
, span
, _
| span
,
177 |c
: ClosureParts
<'_
>| c
.span
,
181 pub fn id(self) -> hir
::HirId
{
183 |i
: ItemFnParts
<'_
>| i
.id
,
184 |id
, _
, _
: &'a hir
::FnSig
<'a
>, _
, _
, _
, _
| id
,
185 |c
: ClosureParts
<'_
>| c
.id
,
189 pub fn constness(self) -> hir
::Constness
{
190 self.kind().header().map_or(hir
::Constness
::NotConst
, |header
| header
.constness
)
193 pub fn asyncness(self) -> hir
::IsAsync
{
194 self.kind().header().map_or(hir
::IsAsync
::NotAsync
, |header
| header
.asyncness
)
197 pub fn unsafety(self) -> hir
::Unsafety
{
198 self.kind().header().map_or(hir
::Unsafety
::Normal
, |header
| header
.unsafety
)
201 pub fn kind(self) -> FnKind
<'a
> {
202 let item
= |p
: ItemFnParts
<'a
>| -> FnKind
<'a
> {
203 FnKind
::ItemFn(p
.ident
, p
.generics
, p
.header
, p
.vis
, p
.attrs
)
205 let closure
= |c
: ClosureParts
<'a
>| FnKind
::Closure(c
.attrs
);
206 let method
= |_
, ident
: Ident
, sig
: &'a hir
::FnSig
<'a
>, vis
, _
, _
, attrs
| {
207 FnKind
::Method(ident
, sig
, vis
, attrs
)
209 self.handle(item
, method
, closure
)
212 fn handle
<A
, I
, M
, C
>(self, item_fn
: I
, method
: M
, closure
: C
) -> A
214 I
: FnOnce(ItemFnParts
<'a
>) -> A
,
219 Option
<&'a hir
::Visibility
<'a
>>,
224 C
: FnOnce(ClosureParts
<'a
>) -> A
,
227 Node
::Item(i
) => match i
.kind
{
228 hir
::ItemKind
::Fn(ref sig
, ref generics
, block
) => item_fn(ItemFnParts
{
239 _
=> bug
!("item FnLikeNode that is not fn-like"),
241 Node
::TraitItem(ti
) => match ti
.kind
{
242 hir
::TraitItemKind
::Method(ref sig
, hir
::TraitMethod
::Provided(body
)) => {
243 method(ti
.hir_id
, ti
.ident
, sig
, None
, body
, ti
.span
, &ti
.attrs
)
245 _
=> bug
!("trait method FnLikeNode that is not fn-like"),
247 Node
::ImplItem(ii
) => match ii
.kind
{
248 hir
::ImplItemKind
::Method(ref sig
, body
) => {
249 method(ii
.hir_id
, ii
.ident
, sig
, Some(&ii
.vis
), body
, ii
.span
, &ii
.attrs
)
251 _
=> bug
!("impl method FnLikeNode that is not fn-like"),
253 Node
::Expr(e
) => match e
.kind
{
254 hir
::ExprKind
::Closure(_
, ref decl
, block
, _fn_decl_span
, _gen
) => {
255 closure(ClosureParts
::new(&decl
, block
, e
.hir_id
, e
.span
, &e
.attrs
))
257 _
=> bug
!("expr FnLikeNode that is not fn-like"),
259 _
=> bug
!("other FnLikeNode that is not fn-like"),