"""
Script to calculate the Cyclomatic Complexity of every function.
Joxean Koret, 2019
Public Domain
"""
import idaapi
#-------------------------------------------------------------------------------
class CCyclomaticComplexityChooser(idaapi.Choose2):
def __init__(self, title, items):
idaapi.Choose2.__init__(self,
title,
[ ["Address", 8], ["Name", 50], ["Nodes", 8],
["Edges", 8], ["CC", 8], ])
self.items = []
for item in items:
element = ["0x%08x" % item[0], item[1],
"%04d" % item[2], "%04d" % item[3], "%04d" % item[4]]
self.items.append(element)
def OnSelectLine(self, n):
ea = int(self.items[n][0], 16)
jumpto(ea)
def OnGetLine(self, n):
return self.items[n]
def OnGetSize(self):
return len(self.items)
#-------------------------------------------------------------------------------
def calc_cc(ea):
func = idaapi.get_func(ea)
if func is not None:
nodes = 0
edges = 0
flow = idaapi.FlowChart(func)
for block in flow:
nodes += 1
for succ in block.succs():
edges += 1
for pred in block.preds():
edges += 1
cc = edges - nodes + 2
return nodes, edges, cc
#-------------------------------------------------------------------------------
def main():
vals = []
items = []
for ea in Functions():
nodes, edges, cc = calc_cc(ea)
name = GetFunctionName(ea)
tmp = Demangle(name, INF_SHORT_DN)
if tmp != "" and tmp is not None:
name = tmp
items.append([ea, name, nodes, edges, cc])
vals.append(cc)
line = "Cyclomatic complexity: Max %d, Avg %d"
print(line % (max(vals), sum(vals)/len(vals)))
ch = CCyclomaticComplexityChooser("Cyclomatic Complexity", items)
ch.Show()
if __name__ == "__main__":
main()
Comments