1- use rustc_hir :: { ExprKind , Item , ItemKind } ;
1+ use indexmap :: IndexSet ;
22use rustc_middle:: ty:: TyCtxt ;
3- use rustc_span:: source_map:: SourceMap ;
3+ use rustc_smir:: rustc_internal:: internal;
4+ use rustc_span:: { Span , source_map:: SourceMap } ;
45use serde:: Serialize ;
6+ use stable_mir:: {
7+ CrateDef , CrateItem , DefId , ItemKind ,
8+ mir:: mono:: Instance ,
9+ ty:: { FnDef , RigidTy , Ty , TyKind } ,
10+ } ;
511
6- mod call_graph ;
12+ mod callees ;
713
814/// A Rust funtion with its file source, attributes, and raw function content.
915#[ derive( Debug , Default , Serialize ) ]
@@ -16,54 +22,84 @@ pub struct Function {
1622 attrs : Vec < String > ,
1723 /// Raw function string, including name, signature, and body.
1824 func : String ,
25+ /// Recursive fnction calls inside the body.
26+ callees : Vec < String > ,
1927}
2028
2129impl Function {
22- pub fn new ( item : & Item , src_map : & SourceMap , tcx : TyCtxt ) -> Option < Self > {
23- if let ItemKind :: Fn { has_body, body, .. } = & item. kind
24- && * has_body
25- {
26- let mut func = Function {
27- file : src_map
28- . span_to_filename ( item. span )
29- . prefer_remapped_unconditionaly ( )
30- . to_string ( ) ,
31- ..Default :: default ( )
32- } ;
30+ pub fn new ( item : CrateItem , tcx : TyCtxt , src_map : & SourceMap ) -> Option < Self > {
31+ if !matches ! ( item. kind( ) , ItemKind :: Fn ) {
32+ // skip non fn items
33+ return None ;
34+ }
35+ // item.emit_mir(&mut std::io::stdout()).unwrap(); // MIR body
36+ let inst = Instance :: try_from ( item) . inspect_err ( |err| error ! ( ?err) ) . ok ( ) ?;
37+ let fn_def = ty_to_fndef ( inst. ty ( ) ) ?;
38+ let file = item. span ( ) . get_filename ( ) ;
39+ let body = fn_def. body ( ) ?;
3340
34- // add attributes
35- for ( i, attr) in tcx. get_all_attrs ( item. owner_id ) . enumerate ( ) {
36- // FIXME: kani rewrites attributes from source to `#[allow(dead_code)]`
37- // and `#[kanitool::...]`, but share the same span with the source span.
38- // As a result, repeated `#[kani::proof]` are obtained from the source text,
39- // but `attr: &AttrItem` contains real expanded attributes.
40- let src_attr = src_map
41- . span_to_source ( attr. span ( ) , |text, x, y| {
42- let src = & text[ x..y] ;
43- debug ! ( "[attr {i}] [{x}:{y}]\n {src}" ) ;
44- Ok ( src. to_owned ( ) )
45- } )
46- . unwrap ( ) ;
47- func. attrs . push ( src_attr) ;
48- }
41+ let mut callees = IndexSet :: new ( ) ;
42+ // retrieve direct calls
43+ callees. extend ( callees:: calls_in_body ( & body) ) ;
44+ // recursive calls
45+ let direct_calls: Vec < _ > = callees. iter ( ) . copied ( ) . collect ( ) ;
46+ for call in direct_calls {
47+ callees:: recursive_callees ( call, & mut callees) ;
48+ }
49+ let callees = callees. into_iter ( ) . map ( |x| format ! ( "{x:?}" ) ) . collect ( ) ;
4950
50- // add function
51- func. func = src_map
52- . span_to_source ( item. span , |text, x, y| {
53- let src = & text[ x..y] ;
54- debug ! ( "[{x}:{y}]\n {src}" ) ;
55- Ok ( src. to_owned ( ) )
56- } )
57- . unwrap ( ) ;
51+ let func = source_code_with ( body. span , tcx, src_map) ;
52+ info ! ( " - {:?} ({:?}): {func}" , item. name( ) , item. span( ) ) ;
5853
59- // dbg!(tcx.hir_body(*body));
60- let fn_body = tcx . hir_body ( * body ) ;
61- if let ExprKind :: Block ( block , _ ) = fn_body . value . kind {
62- dbg ! ( block ) ;
63- }
54+ // FIXME: kanitool and some other proc-macors attributes are generated by parsing,
55+ // and these generated attrs share with span of hand-written attrs in source code.
56+ // As a result, get_all_attributes through source span will emit duplicated attrs.
57+ // Need to fix this in the future, by analyzing Symbols of these attrs.
58+ let attrs = get_all_attributes ( item . def_id ( ) , tcx , src_map ) ;
6459
65- return Some ( func ) ;
66- }
67- None
60+ // TODO: kanitool kind: proof, proof_for_contract, contract, ...
61+
62+ Some ( Function { file , attrs , func , callees } )
6863 }
6964}
65+
66+ /// Extract FnDef from Ty.
67+ fn ty_to_fndef ( ty : Ty ) -> Option < FnDef > {
68+ let TyKind :: RigidTy ( RigidTy :: FnDef ( fn_def, _) ) = ty. kind ( ) else {
69+ return None ;
70+ } ;
71+ Some ( fn_def)
72+ }
73+
74+ /// Source code for a span.
75+ fn source_code ( span : Span , src_map : & SourceMap ) -> String {
76+ src_map
77+ . span_to_source ( span, |text, x, y| {
78+ let src = & text[ x..y] ;
79+ debug ! ( "[{x}:{y}]\n {src}" ) ;
80+ Ok ( src. to_owned ( ) )
81+ } )
82+ . unwrap ( )
83+ }
84+
85+ /// Source code for a stable_mir span.
86+ fn source_code_with (
87+ stable_mir_span : stable_mir:: ty:: Span ,
88+ tcx : TyCtxt ,
89+ src_map : & SourceMap ,
90+ ) -> String {
91+ let span = internal ( tcx, stable_mir_span) ;
92+ source_code ( span, src_map)
93+ }
94+
95+ /// Get all attributes for the item.
96+ ///
97+ /// We don't call [`all_tool_attrs`], because it only gives tool attributes,
98+ /// we want as raw attributes as possible.
99+ ///
100+ /// [`all_tool_attrs`]: https://doc.rust-lang.org/nightly/nightly-rustc/stable_mir/struct.CrateItem.html#impl-CrateDef-for-CrateItem
101+ fn get_all_attributes ( stable_mir_def_id : DefId , tcx : TyCtxt , src_map : & SourceMap ) -> Vec < String > {
102+ let def_id = internal ( tcx, stable_mir_def_id) ;
103+ // dbg!(tcx.hir_body_owned_by(def_id.expect_local())); // HIR body
104+ tcx. get_all_attrs ( def_id) . map ( |attr| source_code ( attr. span ( ) , src_map) ) . collect ( )
105+ }
0 commit comments