Tuesday 19 April 2016

Static static code analyser

I've just been refactoring/rewriting some C++ code and noticed that I've left some static functions around that are unused. "static" in this context means functions that are only accessible within the same file (it's a good idea to put static in front of every function until the point you need to call it from some other file). However, if nothing in the same file calls them, then they contain dead code. Unfortunately neither cppcheck nor MSVC's static code analyser will flag up static functions that are not called, and so I've written my own Python script to do so. It's fairly basic but worked for me.

Update (19/04): Doh! Adding --enable=all to cppcheck will find most (but not all) of these cases.

import os
import sys
import glob

def FindStaticFunctions(fname):
    fns = []
    for line in open(fname):
        tmp = line.strip()
        if not tmp.startswith("static"): continue
        if tmp.endswith(";"): continue
        broken = tmp.split()
        for i, x in enumerate(broken):
            if "(" in x:
                name = x[:x.find("(")].replace("*", "")
            elif i < len(broken)-1 and broken[i+1][0]=='(':
                fns.append(x.replace("*", ""))

    return fns

def FindMissingReferences(fname, staticfns):
    lines = open(fname).readlines()
    for staticfn in staticfns:
        refs = 0
        for line in lines:
            if line.find(staticfn) >= 0:
                refs += 1
        if refs <= 1:
            print "(%s) %s: %d refs" % (os.path.basename(fname), staticfn, refs)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        sys.exit("You need to specify a directory")
    dirname = sys.argv[1]
    if not os.path.isdir(dirname):
        sys.exit("%s is not a directory name" % dirname)

    for cppfile in glob.glob(os.path.join(dirname, "*.cpp")):
        staticfns = FindStaticFunctions(cppfile)
        FindMissingReferences(cppfile, staticfns)