For really cluttered files like [https://github.com/StefanSalewski/gintro/blob/master/tests/gen.nim](https://github.com/StefanSalewski/gintro/blob/master/tests/gen.nim) it is not easy to find code segments which are never executed. In the past I added 'echo' or 'assert false' statements when I assumed that branches are never executed. Yesterday I tried to create a macro for this: # module activeLines import macros, algorithm, strformat type SortObj = object line, cnt: int var lineCT {.compileTime.}: seq[int] line: seq[int] ec = newSeq[int](1024 * 8) # we may use a hash table? macro excnt*(): untyped = let ll = lineinfoObj(result).line lineCT.add(ll) # add the entry when macro is instantiated result = quote do: while line.len < `lineCT`.len: # copy CT seq entries to runtime seq line.add(`lineCT`[line.len]) let (file, line, col) = instantiationInfo() # works at runtime, but is not really needed assert line == `ll` if ec.len <= line: ec.setLen(line + 1) ec[line] += 1 proc excntResult* = var s = newSeq[SortObj](line.len) for i in 0 .. s.high: s[i].line = line[i] s[i].cnt = ec[line[i]] s.sort(proc (x, y: SortObj): int = cmp((x.cnt, x.line), (y.cnt, y.line))) echo "line : activity" template print = echo fmt"{s[i].line:>5}", ": ", s[i].cnt if s.len < 11: for i in 0 .. s.high: print else: for i in 0 .. 4: print echo ".." for i in s.high - 4 .. s.high: print when isMainModule: proc main = excnt() var sum: int excnt() for i in 0 .. 9: excnt() sum += i excnt() if sum < 0: sum = 0; excnt() if sum > 50: sum = 50; excnt() if sum mod 7 == 7: sum = 13; excnt() if 1 > 2: excnt() var a, b: int if a > -1: excnt() if a + b > 0: # to get output for this last always false statement we have to add one additional excnt() excnt() echo "a + b" excnt() # additional dummy one main() excntResult() Run $ nim c --gc:arc -r activeLines/activeLines.nim line : activity 54: 0 56: 0 58: 0 60: 0 65: 0 .. 48: 1 63: 1 67: 1 50: 10 52: 10 Run
Seems to be not that bad. Can we improve it? The copying of the compile time seq into the runtime seq line.add(`lineCT`[line.len]) is a bit strange, but I have found no other way. Also a bit ugly is that to see the last never executed line we have to add on more executed macro call.
