| #!/usr/bin/python |
| |
| import os, sys, re |
| |
| class multidict: |
| def __init__(self, elts=()): |
| self.data = {} |
| for key,value in elts: |
| self[key] = value |
| |
| def __getitem__(self, item): |
| return self.data[item] |
| def __setitem__(self, key, value): |
| if key in self.data: |
| self.data[key].append(value) |
| else: |
| self.data[key] = [value] |
| def items(self): |
| return self.data.items() |
| def values(self): |
| return self.data.values() |
| def keys(self): |
| return self.data.keys() |
| def __len__(self): |
| return len(self.data) |
| |
| kGCCErrorRE = re.compile('(.*):([0-9]+): error: (.*)') |
| kGCCWarningRE = re.compile('(.*):([0-9]+): warning: (.*)') |
| kClangErrorRE = re.compile('(.*):([0-9]+):([0-9]+): error: (.*)') |
| kClangWarningRE = re.compile('(.*):([0-9]+):([0-9]+): warning: (.*)') |
| kAssertionRE = re.compile('Assertion failed: (.*, function .*, file .*, line [0-9]+\\.)') |
| kStackDumpLineRE = re.compile('^[0-9]+ +([^ ]+) +0x[0-9a-fA-F]+ +([^ ]+)') |
| |
| def readInfo(path, opts): |
| f = open(path) |
| data = f.read() |
| f.close() |
| |
| if opts.truncate != -1: |
| data = data[:opts.truncate] |
| |
| gccwarnings = multidict([(m.group(3),m) for m in kGCCWarningRE.finditer(data)]).items() |
| gccerrors = multidict([(m.group(3),m) for m in kGCCErrorRE.finditer(data)]).items() |
| assertions = multidict([(m.group(1),m) for m in kAssertionRE.finditer(data)]).items() |
| |
| # Manual scan for stack traces |
| aborts = multidict() |
| prevLine = None |
| lnIter = iter(data.split('\n')) |
| for ln in lnIter: |
| m = kStackDumpLineRE.match(ln) |
| if m: |
| stack = [m.group(2)] |
| for ln in lnIter: |
| m = kStackDumpLineRE.match(ln) |
| if not m: |
| break |
| stack.append(m.group(2)) |
| if prevLine is None or not kAssertionRE.match(prevLine): |
| aborts[tuple(stack)] = stack |
| prevLine = ln |
| |
| sections = [ |
| (gccwarnings, 'Warnings'), |
| (gccerrors, 'Errors'), |
| (assertions, 'Assertions'), |
| (aborts.items(), 'Aborts'), |
| ] |
| |
| if opts.ascending: |
| sections.reverse() |
| |
| for l,title in sections: |
| l.sort(key = lambda (a,b): -len(b)) |
| if l: |
| print '-- %d %s (%d kinds) --' % (sum([len(b) for a,b in l]), title, len(l)) |
| for name,elts in l: |
| print '%5d:' % len(elts), name |
| |
| def main(): |
| global options |
| from optparse import OptionParser |
| parser = OptionParser("usage: %prog [options] {inputs}") |
| parser.add_option("", "--ascending", dest="ascending", |
| help="Print output in ascending order of severity.", |
| action="store_true", default=False) |
| parser.add_option("", "--truncate", dest="truncate", |
| help="Truncate input file (for testing).", |
| type=int, action="store", default=-1) |
| (opts, args) = parser.parse_args() |
| |
| if not args: |
| parser.error('No inputs specified') |
| |
| for arg in args: |
| readInfo(arg, opts) |
| |
| if __name__=='__main__': |
| main() |