Skip to content

Commit

Permalink
Added solutions to tutorial tasks
Browse files Browse the repository at this point in the history
  • Loading branch information
AryazE committed Feb 20, 2024
1 parent 07e2bbc commit 4574cf5
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typing import Optional
from dynapyt.analyses.BaseAnalysis import BaseAnalysis


class BranchCoverageAnalysis(BaseAnalysis):
def __init__(self):
super().__init__()
self.branches = {}

def enter_control_flow(self, dyn_ast: str, iid: int, cond_value: bool):
if (dyn_ast, iid, cond_value) not in self.branches:
self.branches[(dyn_ast, iid, cond_value)] = 0
self.branches[(dyn_ast, iid, cond_value)] += 1

def end_execution(self):
for k, v in self.branches.items():
print(f"Branch {k[1]} was taken with value {k[2]} {v} times")
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from typing import Callable, Tuple, Dict
import logging
import libcst.matchers as m
from dynapyt.analyses.BaseAnalysis import BaseAnalysis
from dynapyt.utils.nodeLocator import get_parent_by_type
import os
from inspect import getmodule


class CallGraphAnalysis(BaseAnalysis):
def __init__(self):
super(CallGraphAnalysis, self).__init__()
logging.basicConfig(filename="dynapyt.json", format="%(message)s", level=logging.INFO)
self.graph = {}

def pre_call(self, dyn_ast: str, iid: int, function: Callable, pos_args: Tuple, kw_args: Dict):
"""
DynaPyt hook for pre function call
"""
ast, iids = self._get_ast(dyn_ast)
module = getmodule(function)
module = str(module).split(" ")[1] if module is not None else "''"
# calling function
caller = get_parent_by_type(ast, iids.iid_to_location[iid], m.FunctionDef())
# called function
if hasattr(function, "__qualname__"):
# module of the callee is added through the module if present
callee = module[1:-1] + "." + function.__qualname__ if module != "''" else function.__qualname__
else:
# this is done to capture functions whose function.__qualname__ is not defined,
# but the string gives an idea as to which function is called.
# Captures MarkDecorator annotations, lambdas object calls, etc
temp = str(function)
callee = temp

# file name
key = dyn_ast.replace(".py.orig", "").replace(os.sep, ".")
# format = "file"

if caller is None:
f = key
else:
# if caller is a part of class, find the class name
caller_parent = get_parent_by_type(ast, iids.iid_to_location[iid], m.ClassDef())
if caller_parent is None:
f = key + "." + caller.name.value
# format += ".func"
else:
f = key + "." + caller_parent.name.value + "." + caller.name.value
# format += ".class.func"

# if caller already added
if f in self.graph.keys():
temp = self.graph[f]
# filter dupilcate callees
if callee not in temp:
temp.append(callee)
self.graph[f] = temp
else:
# self.graph[f] = [format, callee]
self.graph[f] = [callee]

def end_execution(self):
"""
DynaPyt hook for end of execution
"""
# to avoid serialization failures in converting dict to json
print(self.graph)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from typing import Optional
from dynapyt.analyses.BaseAnalysis import BaseAnalysis


class OppositeBranchAnalysis(BaseAnalysis):
def enter_control_flow(
self, dyn_ast: str, iid: int, cond_value: bool
) -> Optional[bool]:
return not cond_value
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from typing import Iterable
from dynapyt.analyses.BaseAnalysis import BaseAnalysis


class SlowStringConcatAnalysis(BaseAnalysis):
def __init__(self):
super().__init__()
self.in_loop = []
self.concat_count = []
self.threshold = 5

def enter_for(self, dyn_ast: str, iid: int, next_value, iterable: Iterable):
if (
self.in_loop
and self.in_loop[-1][0] == dyn_ast
and self.in_loop[-1][1] == iid
):
pass
else:
self.in_loop.append((dyn_ast, iid))
self.concat_count.append(0)

def exit_for(self, dyn_ast: str, iid: int):
curr = self.in_loop.pop()
assert curr[0] == dyn_ast
assert curr[1] == iid
self.concat_count.pop()

def add_assign(self, dyn_ast: str, iid: int, lhs, rhs):
if self.in_loop:
if isinstance(rhs, str):
self.concat_count[-1] += 1
if self.concat_count[-1] >= self.threshold:
print(f"Possible slow string concatenation in {dyn_ast} at {iid}")

0 comments on commit 4574cf5

Please sign in to comment.