mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-24 00:18:26 +00:00
111 lines
3.6 KiB
Python
111 lines
3.6 KiB
Python
|
"""
|
||
|
Find out which functions are unused in the Monero app - based on
|
||
|
`monero.pyi` file.
|
||
|
"""
|
||
|
|
||
|
import subprocess
|
||
|
import sys
|
||
|
from pathlib import Path
|
||
|
from typing import Any, Dict, List, Set
|
||
|
|
||
|
CURRENT_DIR = Path(__file__).resolve().parent
|
||
|
ROOT_DIR = CURRENT_DIR.parent.parent
|
||
|
|
||
|
HELPER_FILE = ROOT_DIR / "core/src/apps/monero/xmr/crypto_helpers.py"
|
||
|
MOCK_FILE = ROOT_DIR / "core/mocks/generated/trezorcrypto/monero.pyi"
|
||
|
|
||
|
|
||
|
def generate_function_mapping() -> Dict[str, List[str]]:
|
||
|
"""Look at all Monero functions and generate a mapping of their usage"""
|
||
|
|
||
|
# Load all the function names in .pyi file
|
||
|
pyi_functions: Set[str] = set()
|
||
|
with open(MOCK_FILE, "r") as f:
|
||
|
lines = f.readlines()
|
||
|
for line in lines:
|
||
|
if line.startswith("def"):
|
||
|
f_name = line.split("(")[0].split(" ")[1]
|
||
|
pyi_functions.add(f_name)
|
||
|
|
||
|
# Load definitions of helper functions
|
||
|
helper_func_defs: Dict[str, str] = {}
|
||
|
with open(HELPER_FILE, "r") as f:
|
||
|
lines = f.readlines()
|
||
|
current_func = ""
|
||
|
for line in lines:
|
||
|
if line.startswith("def"):
|
||
|
current_func = line.split("(")[0].split(" ")[1]
|
||
|
helper_func_defs[current_func] = line
|
||
|
elif not current_func:
|
||
|
continue
|
||
|
else:
|
||
|
helper_func_defs[current_func] += line
|
||
|
|
||
|
# Try to connect function names with helper definitions
|
||
|
func_mapping: Dict[str, List[str]] = {}
|
||
|
for func_name in pyi_functions:
|
||
|
func_mapping[func_name] = []
|
||
|
for func_def_name, func_code in helper_func_defs.items():
|
||
|
if f".{func_name}(" in func_code:
|
||
|
func_mapping[func_name].append(func_def_name)
|
||
|
|
||
|
# Functions may not be used in helper file, alias them to themselves
|
||
|
if not func_mapping[func_name]:
|
||
|
func_mapping[func_name] = [func_name]
|
||
|
|
||
|
return func_mapping
|
||
|
|
||
|
|
||
|
def check_usage_of_functions(func_mapping: Dict[str, List[str]]) -> None:
|
||
|
"""Go through all the functions and check if they are used in the Monero app.
|
||
|
|
||
|
Generates a report and exits with an appropriate exit code.
|
||
|
"""
|
||
|
|
||
|
# Include boolean field to know what is used
|
||
|
is_used_mappings: Dict[str, Dict[str, Any]] = {}
|
||
|
for func_name, mapping in func_mapping.items():
|
||
|
is_used_mappings[func_name] = {"mapping": mapping, "is_used": False}
|
||
|
|
||
|
# Check if any of the mapping names is used - and mark it as used if so
|
||
|
for func_name in is_used_mappings:
|
||
|
for mapping in is_used_mappings[func_name]["mapping"]:
|
||
|
is_there = _is_used(mapping)
|
||
|
if is_there:
|
||
|
is_used_mappings[func_name]["is_used"] = True
|
||
|
break
|
||
|
|
||
|
# Find unused functions and generate a report
|
||
|
unused_functions = {
|
||
|
fc: val for fc, val in is_used_mappings.items() if not val["is_used"]
|
||
|
}
|
||
|
if not unused_functions:
|
||
|
print("SUCCESS: no functions are unused")
|
||
|
sys.exit(0)
|
||
|
else:
|
||
|
print(f"{len(unused_functions)} unused functions:")
|
||
|
for func, values in unused_functions.items():
|
||
|
print(func, values)
|
||
|
sys.exit(1)
|
||
|
|
||
|
|
||
|
def _is_used(func_name: str) -> bool:
|
||
|
"""Find function usage in the Monero app or in test files"""
|
||
|
|
||
|
cmds = [
|
||
|
rf'grep -r ".{func_name}\b" {ROOT_DIR}/core/src/apps/monero',
|
||
|
rf'grep -r ".{func_name}\b" {ROOT_DIR}/core/tests',
|
||
|
]
|
||
|
|
||
|
for cmd in cmds:
|
||
|
grep_result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE)
|
||
|
if grep_result.returncode == 0:
|
||
|
return True
|
||
|
|
||
|
return False
|
||
|
|
||
|
|
||
|
if "__main__" == __name__:
|
||
|
func_mapping = generate_function_mapping()
|
||
|
check_usage_of_functions(func_mapping)
|