1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5import json 6import subprocess 7 8cached_functions = {} 9 10 11def getMetricsJson(src_url): 12 print("Fetching source for function extraction: {}".format(src_url)) 13 metrics = subprocess.check_output(["./fetch_fn_names.sh", src_url]) 14 15 try: 16 return json.loads(metrics) 17 except ValueError: 18 return {"kind": "empty", "name": "anonymous", "spaces": []} 19 20 21def getSpaceFunctionsRecursive(metrics_space): 22 functions = [] 23 if ( 24 metrics_space["kind"] == "function" 25 and metrics_space["name"] 26 and metrics_space["name"] != "<anonymous>" 27 ): 28 functions.append( 29 { 30 "name": metrics_space["name"], 31 "start_line": int(metrics_space["start_line"]), 32 "end_line": int(metrics_space["end_line"]), 33 } 34 ) 35 for space in metrics_space["spaces"]: 36 functions += getSpaceFunctionsRecursive(space) 37 return functions 38 39 40def getSourceFunctions(src_url): 41 if src_url not in cached_functions: 42 metrics_space = getMetricsJson(src_url) 43 cached_functions[src_url] = getSpaceFunctionsRecursive(metrics_space) 44 45 return cached_functions[src_url] 46 47 48def getFunctionName(location): 49 location.replace("annotate", "raw-file") 50 pieces = location.split("#l") 51 src_url = pieces[0] 52 line = int(pieces[1]) 53 closest_name = "<Unknown {}>".format(line) 54 closest_start = 0 55 functions = getSourceFunctions(src_url) 56 for fn in functions: 57 if ( 58 fn["start_line"] > closest_start 59 and line >= fn["start_line"] 60 and line <= fn["end_line"] 61 ): 62 closest_start = fn["start_line"] 63 closest_name = fn["name"] 64 return closest_name 65