#!/usr/bin/env python # # Copyright (c) 2011 Apple Inc. All rights reserved. # # This document is the property of Apple Inc. # It is considered confidential and proprietary. # # This document may not be reproduced or transmitted in any form, # in whole or in part, without the express written permission of # Apple Inc. # import os import sys import linecache import cgi import operator import xml.sax.saxutils as saxutils Usage=''' analyzer-report build_output_dir suppressfile ''' ignored_hashes = None def get_source_line(filename, linenum): return linecache.getline(filename, int(linenum)).strip(); def process_report_file(filename): buginfo={} def populate(comment_name, friendly_name, line): if friendly_name not in buginfo and comment_name in line: front_slice = len("") buginfo[friendly_name] = line[front_slice:-end_slice].strip() return True; return False; actions = { "*****Not a filename*******": "report_file", "BUGDESC": "description", "BUGTYPE": "type", "BUGCATEGORY": "category", "BUGFILE": "source_file", "BUGLINE": "line_num"} buginfo['report_file'] = filename with open(filename) as f: for line in f: try: for (cn, fn) in actions.items(): if populate(cn, fn, line): raise ValueError, "Continue" except ValueError: continue # Lazy hack. Nothing in here uses ValueError. if set(actions.values()) == set(buginfo.keys()): buginfo["source_line"] = get_source_line(buginfo['source_file'], buginfo['line_num']); return buginfo return None ''' Turns a buginfo dict into a "stable" bug hash. This is meant to be used to mark problems as ignored. ''' def bughash(buginfo): return "[%s # %s # %s]" % (buginfo['description'], buginfo['source_line'], os.path.basename(buginfo['source_file'])) def generate_report_file(buginfos, misc, outfile): with(open(outfile, "w")) as out: print >>out, "Clang analyzer report for %s" % sys.argv[1] print >>out, "" for bug in sorted(buginfos, key=operator.itemgetter('source_file', 'description')): if is_ignored(bughash(bug)): continue print >>out, " \n" print >>out, " \n".format(saxutils.quoteattr(bug['report_file']), saxutils.escape(bug['source_file'])) print >>out, " \n".format(saxutils.escape(bug['description'])) print >>out, " \n".format(saxutils.quoteattr(bughash(bug))) print >>out, " \n" print >>out, "
Source fileBug descriptionbughash
{}{}

%s
" % saxutils.escape(misc) def is_ignored(i): global ignored_hashes if ignored_hashes is None: ignored_hashes = set() for line in open(ignorefile): if line.strip() and not line.startswith("#"): ignored_hashes.add(line.strip()) return i in ignored_hashes def run_misc(buginfos): import cStringIO s = cStringIO.StringIO() ignored = [bughash(i) for i in buginfos if is_ignored(bughash(i))] not_ignored = [bughash(i) for i in buginfos if not is_ignored(bughash(i))] print >>s, "Ignored %d bug(s) because of suppress file" % len(ignored) if ignored_hashes: for h in ignored_hashes: if h not in ignored: print >>s, "Warning: Possible stale bughash in suppress file: %s" % h return s.getvalue() ignorefile = os.path.abspath(sys.argv[2]) os.chdir(sys.argv[1]) buginfos=[] for folder, subs, files in os.walk("."): for fn in files: if fn.endswith(".html"): buginfo = process_report_file(os.path.join(folder,fn)) if(buginfo): buginfos.append(buginfo) generate_report_file(buginfos, run_misc(buginfos), "index.html")