summaryrefslogtreecommitdiffstats
path: root/dom/quota/scripts/qm-try-analysis/qm_try_analysis/fn_anchors.py
blob: 13e3802399fe83028ecb445eb1ac70035bf89c2e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import json
import subprocess
from os import path

from qm_try_analysis.logging import info, warning

cached_functions = {}


def getMetricsJson(src_url):
    if src_url.startswith("http"):
        info(f"Fetching source for function extraction: {src_url}")
        metrics = subprocess.check_output(
            [
                path.join(path.dirname(path.realpath(__file__)), "fetch_fn_names.sh"),
                src_url,
            ]
        )
    else:
        warning(f"Skip fetching source: {src_url}")
        metrics = ""

    try:
        return json.loads(metrics)
    except ValueError:
        return {"kind": "empty", "name": "anonymous", "spaces": []}


def getSpaceFunctionsRecursive(metrics_space):
    functions = []
    if (
        metrics_space["kind"] == "function"
        and metrics_space["name"]
        and metrics_space["name"] != "<anonymous>"
    ):
        functions.append(
            {
                "name": metrics_space["name"],
                "start_line": int(metrics_space["start_line"]),
                "end_line": int(metrics_space["end_line"]),
            }
        )
    for space in metrics_space["spaces"]:
        functions += getSpaceFunctionsRecursive(space)
    return functions


def getSourceFunctions(src_url):
    if src_url not in cached_functions:
        metrics_space = getMetricsJson(src_url)
        cached_functions[src_url] = getSpaceFunctionsRecursive(metrics_space)

    return cached_functions[src_url]


def getFunctionName(location):
    location.replace("annotate", "raw-file")
    pieces = location.split("#l")
    src_url = pieces[0]
    line = int(pieces[1])
    closest_name = "<Unknown {}>".format(line)
    closest_start = 0
    functions = getSourceFunctions(src_url)
    for fn in functions:
        if (
            fn["start_line"] > closest_start
            and line >= fn["start_line"]
            and line <= fn["end_line"]
        ):
            closest_start = fn["start_line"]
            closest_name = fn["name"]
    return closest_name