|   | 47 |   | 
                  
                          |   | 48 | {{{#!comment  | 
                  
                          |   | 49 |   | 
                  
                          |   | 50 | == Configurable dynamic function analyzer ==  | 
                  
                          |   | 51 |   | 
                  
                          |   | 52 | Dynamic function analyzer was extended to handle user defined functions that has semantics similar to apply BIF.  | 
                  
                          |   | 53 |   | 
                  
                          |   | 54 | In Erlang it is sometimes preferable to use custom functions that act as a wrapper for a simple apply.   | 
                  
                          |   | 55 | For example for load distribution among different Erlang nodes. Or implementing callback functions.  | 
                  
                          |   | 56 |   | 
                  
                          |   | 57 | === Small example ===  | 
                  
                          |   | 58 |   | 
                  
                          |   | 59 | Consider the following small example.  | 
                  
                          |   | 60 |   | 
                  
                          |   | 61 | The module which is going to be analyzed.  | 
                  
                          |   | 62 | {{{#!erlang  | 
                  
                          |   | 63 | -module(dynfun_example).  | 
                  
                          |   | 64 | -compile(export_all).  | 
                  
                          |   | 65 |   | 
                  
                          |   | 66 | a()->  | 
                  
                          |   | 67 |     1.  | 
                  
                          |   | 68 |   | 
                  
                          |   | 69 | b()->  | 
                  
                          |   | 70 |     erlang:apply(?MODULE, a, []).  | 
                  
                          |   | 71 | }}}  | 
                  
                          |   | 72 |   | 
                  
                          |   | 73 | The configuration file, which is located at the tool root, and is called {{{dynfunref.conf}}}:  | 
                  
                          |   | 74 | {{{#!erlang  | 
                  
                          |   | 75 | {  | 
                  
                          |   | 76 | {erlang, apply},  | 
                  
                          |   | 77 | ['$1', '$2', '$3'],  | 
                  
                          |   | 78 | [{'$1', '$2', '$3'}]  | 
                  
                          |   | 79 | }.  | 
                  
                          |   | 80 | }}}  | 
                  
                          |   | 81 |   | 
                  
                          |   | 82 | The result:  | 
                  
                          |   | 83 | {{{#!erlang  | 
                  
                          |   | 84 | (refactorerl@localhost)8> ri:reset().                            | 
                  
                          |   | 85 | {ok,[]}  | 
                  
                          |   | 86 | ok  | 
                  
                          |   | 87 | (refactorerl@localhost)9> ri:add("/Users/V/erlang/dynfun_766").  | 
                  
                          |   | 88 | | 1.22 kB/s >>>>>>>>>>>>>>>>>>>| [   4/   4] dynfun_example.erl  | 
                  
                          |   | 89 | ok  | 
                  
                          |   | 90 | (refactorerl@localhost)10> ri:q("mods.funs.dyncalls").            | 
                  
                          |   | 91 | ok  | 
                  
                          |   | 92 | (refactorerl@localhost)11> ri:anal_dyn().                         | 
                  
                          |   | 93 | Function reference patterns loaded (1, dynfunref.conf)  | 
                  
                          |   | 94 |   | 
                  
                          |   | 95 | Analysing local funs... (0 done).                                                | 
                  
                          |   | 96 | Collecting function calls...  | 
                  
                          |   | 97 | 1 function calls found in the database.  | 
                  
                          |   | 98 | Looking for dynamic references...  | 
                  
                          |   | 99 | 1 dynamic function references found.  | 
                  
                          |   | 100 | Inspecting dynamic references... (1/1)  | 
                  
                          |   | 101 | 1 potential callee successfully spotted.  | 
                  
                          |   | 102 | Storing dynamic references... (1/1)  | 
                  
                          |   | 103 | Updating the call graph... (1/1)  | 
                  
                          |   | 104 |   | 
                  
                          |   | 105 | Analysis completed.  | 
                  
                          |   | 106 | ok  | 
                  
                          |   | 107 | (refactorerl@localhost)12> ri:q("mods.funs.dyncalls").            | 
                  
                          |   | 108 | dynfun_example:b/0  | 
                  
                          |   | 109 |     dynfun_example:a/0  | 
                  
                          |   | 110 | ok  | 
                  
                          |   | 111 | }}}  | 
                  
                          |   | 112 |   | 
                  
                          |   | 113 | A user-defined references to link from the original function call was made.   | 
                  
                          |   | 114 |   | 
                  
                          |   | 115 | === How to specify a valid Erlang match specification ===  | 
                  
                          |   | 116 | {{{#!erlang  | 
                  
                          |   | 117 | {  | 
                  
                          |   | 118 | {erlang, apply},       %analyzed module and function  | 
                  
                          |   | 119 | ['$1', '$2', '$3'],    %match  | 
                  
                          |   | 120 | [{'$1', '$2', '$3'}]   %where to link (an exact function)  | 
                  
                          |   | 121 | }.  | 
                  
                          |   | 122 | }}}  | 
                  
                          |   | 123 | The first element of the tuple is a tuple, which first element is the name of the module in which the analyzed function is located. The name of the function is at the second element.   | 
                  
                          |   | 124 | The second element is a list of match specs. Its length equals to the arity of the analyzed function.   | 
                  
                          |   | 125 | The third argument is a list of mappings represented by tuples. One element of a mapping is a 3-tuple representing an exact function. The third element is represent arity rather than agrments.  | 
                  
                          |   | 126 |   | 
                  
                          |   | 127 | === Another example ===  | 
                  
                          |   | 128 | Consider the following 2 module.  | 
                  
                          |   | 129 | {{{#!erlang  | 
                  
                          |   | 130 | -module(router).  | 
                  
                          |   | 131 | -export([route/2]).  | 
                  
                          |   | 132 |   | 
                  
                          |   | 133 | route(ReqID, Args)->  | 
                  
                          |   | 134 |     [Function | Args0] = tuple_to_list(Args),  | 
                  
                          |   | 135 |     Master =self(),      | 
                  
                          |   | 136 |     Worker = fun()->  | 
                  
                          |   | 137 |         Result = try  | 
                  
                          |   | 138 |             apply(router_backend, Function, [ReqID]++Args0)  | 
                  
                          |   | 139 |         catch  | 
                  
                          |   | 140 |             _ -> error  | 
                  
                          |   | 141 |         end,  | 
                  
                          |   | 142 |         Master ! {ReqID, Result}  | 
                  
                          |   | 143 |         end,  | 
                  
                          |   | 144 |     spawn(Worker),  | 
                  
                          |   | 145 |     receive  | 
                  
                          |   | 146 |          {ReqID, Result} -> Result  | 
                  
                          |   | 147 |     end.  | 
                  
                          |   | 148 |       | 
                  
                          |   | 149 | ex_call()->  | 
                  
                          |   | 150 |     route(1, {a}).  | 
                  
                          |   | 151 |   | 
                  
                          |   | 152 | ex_call2()->  | 
                  
                          |   | 153 |     route(2,{b,1}).  | 
                  
                          |   | 154 | }}}  | 
                  
                          |   | 155 |   | 
                  
                          |   | 156 | {{{#!erlang  | 
                  
                          |   | 157 | -module(router_backend).  | 
                  
                          |   | 158 | -compile(export_all).  | 
                  
                          |   | 159 |   | 
                  
                          |   | 160 | a(_)->  | 
                  
                          |   | 161 |     2.  | 
                  
                          |   | 162 |   | 
                  
                          |   | 163 | b(_,A)->  | 
                  
                          |   | 164 |     A+1.  | 
                  
                          |   | 165 | }}}  | 
                  
                          |   | 166 |   | 
                  
                          |   | 167 | The configuration file:  | 
                  
                          |   | 168 | {{{#!erlang  | 
                  
                          |   | 169 | %will link router_backend:a/1 to router:ex_call/0  | 
                  
                          |   | 170 | {{router,route},  | 
                  
                          |   | 171 | ['_', {'$1'}],  | 
                  
                          |   | 172 | [  | 
                  
                          |   | 173 |     {router_backend, '$1', 1}  | 
                  
                          |   | 174 | ]}.  | 
                  
                          |   | 175 |   | 
                  
                          |   | 176 | %will link router_backend:b/2 to router:ex_call2/0  | 
                  
                          |   | 177 | {{router,route},  | 
                  
                          |   | 178 | ['_', {'$1','_'}],  | 
                  
                          |   | 179 | [  | 
                  
                          |   | 180 |     {router_backend, '$1', 2}  | 
                  
                          |   | 181 | ]}.  | 
                  
                          |   | 182 | }}}  | 
                  
                          |   | 183 |   | 
                  
                          |   | 184 |   | 
                  
                          |   | 185 | The result:  | 
                  
                          |   | 186 | {{{#!erlang  | 
                  
                          |   | 187 | (refactorerl@localhost)26> ri:reset().                             | 
                  
                          |   | 188 | {ok,[]}  | 
                  
                          |   | 189 | ok  | 
                  
                          |   | 190 | (refactorerl@localhost)27> ri:add("/Users/V/erlang/mini_router").  | 
                  
                          |   | 191 | | 1.12 kB/s >>>>>>>>>>>>>>>>>>>| [   4/   4] router.erl  | 
                  
                          |   | 192 | | 1.18 kB/s >>>>>>>>>>>>>>>>>>>| [   4/   4] router_backend.erl  | 
                  
                          |   | 193 | ok  | 
                  
                          |   | 194 | (refactorerl@localhost)28> ri:anal_dyn().  | 
                  
                          |   | 195 | Function reference patterns loaded (2, dynfunref.conf)  | 
                  
                          |   | 196 |   | 
                  
                          |   | 197 | Analysing local funs... (1 done).                                                | 
                  
                          |   | 198 | Collecting function calls...  | 
                  
                          |   | 199 | 6 function calls found in the database.  | 
                  
                          |   | 200 | Looking for dynamic references...  | 
                  
                          |   | 201 | 5 dynamic function references found.  | 
                  
                          |   | 202 | Inspecting dynamic references... (5/5)  | 
                  
                          |   | 203 | 3 potential callee successfully spotted.  | 
                  
                          |   | 204 | Storing dynamic references... (3/3)  | 
                  
                          |   | 205 | Updating the call graph... (3/3)  | 
                  
                          |   | 206 |   | 
                  
                          |   | 207 | Analysis completed.  | 
                  
                          |   | 208 | ok  | 
                  
                          |   | 209 | (refactorerl@localhost)29> ri:q("mods.funs.dyncalls").  | 
                  
                          |   | 210 | router:ex_call/0  | 
                  
                          |   | 211 |     router_backend:a/1  | 
                  
                          |   | 212 | router:ex_call2/0  | 
                  
                          |   | 213 |     router_backend:b/2  | 
                  
                          |   | 214 | ok  | 
                  
                          |   | 215 | }}}  | 
                  
                          |   | 216 |   | 
                  
                          |   | 217 | A dynamic function reference were made to link {{{router_backend:a/1}}} to {{{router:ex_call/0 }}},  | 
                  
                          |   | 218 | and to link {{{router_backend:b/2}}} to {{{router:ex_call2/0}}}.  | 
                  
                          |   | 219 | }}}  |