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
as ast
;
16 use crate::hir
::{Expr, FnDecl, Node}
;
17 use crate::hir
::intravisit
::FnKind
;
18 use syntax
::ast
::{Attribute, Ident, NodeId}
;
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
> { node: Node<'a> }
34 /// MaybeFnLike wraps a method that indicates if an object
35 /// corresponds to some FnLikeNode.
36 trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
38 impl MaybeFnLike
for ast
::Item
{
39 fn is_fn_like(&self) -> bool
{
40 match self.node { ast::ItemKind::Fn(..) => true, _ => false, }
44 impl MaybeFnLike
for ast
::ImplItem
{
45 fn is_fn_like(&self) -> bool
{
46 match self.node { ast::ImplItemKind::Method(..) => true, _ => false, }
50 impl MaybeFnLike
for ast
::TraitItem
{
51 fn is_fn_like(&self) -> bool
{
53 ast
::TraitItemKind
::Method(_
, ast
::TraitMethod
::Provided(_
)) => true,
59 impl MaybeFnLike
for ast
::Expr
{
60 fn is_fn_like(&self) -> bool
{
62 ast
::ExprKind
::Closure(..) => true,
68 /// Carries either an FnLikeNode or a Expr, as these are the two
69 /// constructs that correspond to "code" (as in, something from which
70 /// we can construct a control-flow graph).
71 #[derive(Copy, Clone)]
73 FnLike(FnLikeNode
<'a
>),
78 pub fn id(&self) -> NodeId
{
80 Code
::FnLike(node
) => node
.id(),
81 Code
::Expr(block
) => block
.id
,
85 /// Attempts to construct a Code from presumed FnLike or Expr node input.
86 pub fn from_node(map
: &map
::Map
<'a
>, id
: NodeId
) -> Option
<Code
<'a
>> {
88 map
::Node
::Block(_
) => {
89 // Use the parent, hopefully an expression node.
90 Code
::from_node(map
, map
.get_parent_node(id
))
92 map
::Node
::Expr(expr
) => Some(Code
::Expr(expr
)),
93 node
=> FnLikeNode
::from_node(node
).map(Code
::FnLike
)
98 /// These are all the components one can extract from a fn item for
99 /// use when implementing FnLikeNode operations.
100 struct ItemFnParts
<'a
> {
102 decl
: &'a ast
::FnDecl
,
103 header
: ast
::FnHeader
,
104 vis
: &'a ast
::Visibility
,
105 generics
: &'a ast
::Generics
,
109 attrs
: &'a
[Attribute
],
112 /// These are all the components one can extract from a closure expr
113 /// for use when implementing FnLikeNode operations.
114 struct ClosureParts
<'a
> {
119 attrs
: &'a
[Attribute
],
122 impl<'a
> ClosureParts
<'a
> {
123 fn new(d
: &'a FnDecl
, b
: ast
::BodyId
, id
: NodeId
, s
: Span
, attrs
: &'a
[Attribute
]) -> Self {
134 impl<'a
> FnLikeNode
<'a
> {
135 /// Attempts to construct a FnLikeNode from presumed FnLike node input.
136 pub fn from_node(node
: Node
<'_
>) -> Option
<FnLikeNode
<'_
>> {
137 let fn_like
= match node
{
138 map
::Node
::Item(item
) => item
.is_fn_like(),
139 map
::Node
::TraitItem(tm
) => tm
.is_fn_like(),
140 map
::Node
::ImplItem(it
) => it
.is_fn_like(),
141 map
::Node
::Expr(e
) => e
.is_fn_like(),
153 pub fn body(self) -> ast
::BodyId
{
154 self.handle(|i
: ItemFnParts
<'a
>| i
.body
,
155 |_
, _
, _
: &'a ast
::MethodSig
, _
, body
: ast
::BodyId
, _
, _
| body
,
156 |c
: ClosureParts
<'a
>| c
.body
)
159 pub fn decl(self) -> &'a FnDecl
{
160 self.handle(|i
: ItemFnParts
<'a
>| &*i
.decl
,
161 |_
, _
, sig
: &'a ast
::MethodSig
, _
, _
, _
, _
| &sig
.decl
,
162 |c
: ClosureParts
<'a
>| c
.decl
)
165 pub fn span(self) -> Span
{
166 self.handle(|i
: ItemFnParts
<'_
>| i
.span
,
167 |_
, _
, _
: &'a ast
::MethodSig
, _
, _
, span
, _
| span
,
168 |c
: ClosureParts
<'_
>| c
.span
)
171 pub fn id(self) -> NodeId
{
172 self.handle(|i
: ItemFnParts
<'_
>| i
.id
,
173 |id
, _
, _
: &'a ast
::MethodSig
, _
, _
, _
, _
| id
,
174 |c
: ClosureParts
<'_
>| c
.id
)
177 pub fn constness(self) -> ast
::Constness
{
179 FnKind
::ItemFn(_
, _
, header
, ..) => header
.constness
,
180 FnKind
::Method(_
, m
, ..) => m
.header
.constness
,
181 _
=> ast
::Constness
::NotConst
185 pub fn asyncness(self) -> ast
::IsAsync
{
187 FnKind
::ItemFn(_
, _
, header
, ..) => header
.asyncness
,
188 FnKind
::Method(_
, m
, ..) => m
.header
.asyncness
,
189 _
=> ast
::IsAsync
::NotAsync
193 pub fn unsafety(self) -> ast
::Unsafety
{
195 FnKind
::ItemFn(_
, _
, header
, ..) => header
.unsafety
,
196 FnKind
::Method(_
, m
, ..) => m
.header
.unsafety
,
197 _
=> ast
::Unsafety
::Normal
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
>| {
206 FnKind
::Closure(c
.attrs
)
208 let method
= |_
, ident
: Ident
, sig
: &'a ast
::MethodSig
, vis
, _
, _
, attrs
| {
209 FnKind
::Method(ident
, sig
, vis
, attrs
)
211 self.handle(item
, method
, closure
)
214 fn handle
<A
, I
, M
, C
>(self, item_fn
: I
, method
: M
, closure
: C
) -> A
where
215 I
: FnOnce(ItemFnParts
<'a
>) -> A
,
219 Option
<&'a ast
::Visibility
>,
224 C
: FnOnce(ClosureParts
<'a
>) -> A
,
227 map
::Node
::Item(i
) => match i
.node
{
228 ast
::ItemKind
::Fn(ref decl
, header
, ref generics
, block
) =>
229 item_fn(ItemFnParts
{
240 _
=> bug
!("item FnLikeNode that is not fn-like"),
242 map
::Node
::TraitItem(ti
) => match ti
.node
{
243 ast
::TraitItemKind
::Method(ref sig
, ast
::TraitMethod
::Provided(body
)) => {
244 method(ti
.id
, ti
.ident
, sig
, None
, body
, ti
.span
, &ti
.attrs
)
246 _
=> bug
!("trait method FnLikeNode that is not fn-like"),
248 map
::Node
::ImplItem(ii
) => {
250 ast
::ImplItemKind
::Method(ref sig
, body
) => {
251 method(ii
.id
, ii
.ident
, sig
, Some(&ii
.vis
), body
, ii
.span
, &ii
.attrs
)
253 _
=> bug
!("impl method FnLikeNode that is not fn-like")
256 map
::Node
::Expr(e
) => match e
.node
{
257 ast
::ExprKind
::Closure(_
, ref decl
, block
, _fn_decl_span
, _gen
) =>
258 closure(ClosureParts
::new(&decl
, block
, e
.id
, e
.span
, &e
.attrs
)),
259 _
=> bug
!("expr FnLikeNode that is not fn-like"),
261 _
=> bug
!("other FnLikeNode that is not fn-like"),