Args: class_name: A String, name of the class this function belongs to G: A nx.DiGraph object, storing the actual call graph new_func: A dictionary, mapping a new function's identifer (fid) to its size fid_to_file: A dictionary, mapping fid to the fil
(func_node, class_name, G, new_func, fid_to_file, env)
| 184 | |
| 185 | |
| 186 | def handle_func_node(func_node, class_name, G, new_func, fid_to_file, env): |
| 187 | """ |
| 188 | Args: |
| 189 | class_name: A String, name of the class this function belongs to |
| 190 | G: A nx.DiGraph object, storing the actual call graph |
| 191 | new_func: A dictionary, mapping a new function's identifer (fid) |
| 192 | to its size |
| 193 | fid_to_file: A dictionary, mapping fid to the file it belongs to |
| 194 | env: A dictionary, storing global environment |
| 195 | |
| 196 | Workflow Summary: |
| 197 | 1. Parse function name and generate fid |
| 198 | 2. Add caller function to call graph G |
| 199 | 3. Initialize local_env by parsing parameter list |
| 200 | 4. Iterate through subnodes of this function in document order |
| 201 | a. For <call> node, parse it and get callee_fid, |
| 202 | add this new edge to call graph G |
| 203 | b. For <decl> node, parse it and update local_env |
| 204 | |
| 205 | Node Structure: |
| 206 | <function> node's direct children include <name>, <specifier>, |
| 207 | <block>, <parameter_list> |
| 208 | |
| 209 | TODOs: |
| 210 | 1. Function Overload |
| 211 | a. Primitive type |
| 212 | 2. Polymorphism |
| 213 | 3. Collection |
| 214 | 4. Array |
| 215 | 5. Add logic to remove variable from local_env |
| 216 | 6. Nested class |
| 217 | 7. Anonymous class |
| 218 | """ |
| 219 | name_node = func_node.find('./srcml:name', ns) |
| 220 | block_node = func_node.find('./srcml:block', ns) |
| 221 | block_pos_node = block_node.find('./pos:position', ns) |
| 222 | if block_pos_node is None: |
| 223 | # probably a srcML parsing error |
| 224 | return |
| 225 | param_lst_node = func_node.find('./srcml:parameter_list', ns) |
| 226 | |
| 227 | func_name = get_name(func_node) |
| 228 | caller_fid = generate_fid(class_name, func_name) |
| 229 | start_line = int(name_node.attrib[line_attr]) |
| 230 | end_line = int(block_pos_node.attrib[line_attr]) |
| 231 | num_lines = end_line - start_line + 1 |
| 232 | |
| 233 | # local_env maps variable name to class name |
| 234 | try: |
| 235 | local_env = handle_param_lst_node(param_lst_node) |
| 236 | except: |
| 237 | print("Failed to parse parameter list for %s" % caller_fid) |
| 238 | return |
| 239 | |
| 240 | if caller_fid not in G: |
| 241 | # Case 1: hasn't been defined and hasn't been called |
| 242 | new_func[caller_fid] = num_lines |
| 243 | G.add_node(caller_fid, {'num_lines': num_lines, 'defined': True}) |
no test coverage detected