diff options
Diffstat (limited to 'contrib/llvm/tools/clang/utils/analyzer/CmpRuns')
-rwxr-xr-x | contrib/llvm/tools/clang/utils/analyzer/CmpRuns | 230 |
1 files changed, 0 insertions, 230 deletions
diff --git a/contrib/llvm/tools/clang/utils/analyzer/CmpRuns b/contrib/llvm/tools/clang/utils/analyzer/CmpRuns deleted file mode 100755 index 739d584..0000000 --- a/contrib/llvm/tools/clang/utils/analyzer/CmpRuns +++ /dev/null @@ -1,230 +0,0 @@ -#!/usr/bin/env python - -""" -CmpRuns - A simple tool for comparing two static analyzer runs to determine -which reports have been added, removed, or changed. - -This is designed to support automated testing using the static analyzer, from -two perspectives: - 1. To monitor changes in the static analyzer's reports on real code bases, for - regression testing. - - 2. For use by end users who want to integrate regular static analyzer testing - into a buildbot like environment. -""" - -import os -import plistlib - -# - -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) - def get(self, key, default=None): - return self.data.get(key, default) - -# - -class AnalysisReport: - def __init__(self, run, files): - self.run = run - self.files = files - -class AnalysisDiagnostic: - def __init__(self, data, report, htmlReport): - self.data = data - self.report = report - self.htmlReport = htmlReport - - def getReadableName(self): - loc = self.data['location'] - filename = self.report.run.getSourceName(self.report.files[loc['file']]) - line = loc['line'] - column = loc['col'] - - # FIXME: Get a report number based on this key, to 'distinguish' - # reports, or something. - - return '%s:%d:%d' % (filename, line, column) - - def getReportData(self): - if self.htmlReport is None: - return "This diagnostic does not have any report data." - - return open(os.path.join(self.report.run.path, - self.htmlReport), "rb").read() - -class AnalysisRun: - def __init__(self, path, opts): - self.path = path - self.reports = [] - self.diagnostics = [] - self.opts = opts - - def getSourceName(self, path): - if path.startswith(self.opts.root): - return path[len(self.opts.root):] - return path - -def loadResults(path, opts): - run = AnalysisRun(path, opts) - - for f in os.listdir(path): - if (not f.startswith('report') or - not f.endswith('plist')): - continue - - p = os.path.join(path, f) - data = plistlib.readPlist(p) - - # Ignore empty reports. - if not data['files']: - continue - - # Extract the HTML reports, if they exists. - if 'HTMLDiagnostics_files' in data['diagnostics'][0]: - htmlFiles = [] - for d in data['diagnostics']: - # FIXME: Why is this named files, when does it have multiple - # files? - assert len(d['HTMLDiagnostics_files']) == 1 - htmlFiles.append(d.pop('HTMLDiagnostics_files')[0]) - else: - htmlFiles = [None] * len(data['diagnostics']) - - report = AnalysisReport(run, data.pop('files')) - diagnostics = [AnalysisDiagnostic(d, report, h) - for d,h in zip(data.pop('diagnostics'), - htmlFiles)] - - assert not data - - run.reports.append(report) - run.diagnostics.extend(diagnostics) - - return run - -def compareResults(A, B): - """ - compareResults - Generate a relation from diagnostics in run A to - diagnostics in run B. - - The result is the relation as a list of triples (a, b, confidence) where - each element {a,b} is None or an element from the respective run, and - confidence is a measure of the match quality (where 0 indicates equality, - and None is used if either element is None). - """ - - res = [] - - # Quickly eliminate equal elements. - neqA = [] - neqB = [] - eltsA = list(A.diagnostics) - eltsB = list(B.diagnostics) - eltsA.sort(key = lambda d: d.data) - eltsB.sort(key = lambda d: d.data) - while eltsA and eltsB: - a = eltsA.pop() - b = eltsB.pop() - if a.data == b.data: - res.append((a, b, 0)) - elif a.data > b.data: - neqA.append(a) - eltsB.append(b) - else: - neqB.append(b) - eltsA.append(a) - neqA.extend(eltsA) - neqB.extend(eltsB) - - # FIXME: Add fuzzy matching. One simple and possible effective idea would be - # to bin the diagnostics, print them in a normalized form (based solely on - # the structure of the diagnostic), compute the diff, then use that as the - # basis for matching. This has the nice property that we don't depend in any - # way on the diagnostic format. - - for a in neqA: - res.append((a, None, None)) - for b in neqB: - res.append((None, b, None)) - - return res - -def main(): - from optparse import OptionParser - parser = OptionParser("usage: %prog [options] [dir A] [dir B]") - parser.add_option("", "--root", dest="root", - help="Prefix to ignore on source files", - action="store", type=str, default="") - parser.add_option("", "--verbose-log", dest="verboseLog", - help="Write additional information to LOG [default=None]", - action="store", type=str, default=None, - metavar="LOG") - (opts, args) = parser.parse_args() - - if len(args) != 2: - parser.error("invalid number of arguments") - - dirA,dirB = args - - # Load the run results. - resultsA = loadResults(dirA, opts) - resultsB = loadResults(dirB, opts) - - # Open the verbose log, if given. - if opts.verboseLog: - auxLog = open(opts.verboseLog, "wb") - else: - auxLog = None - - diff = compareResults(resultsA, resultsB) - for res in diff: - a,b,confidence = res - if a is None: - print "ADDED: %r" % b.getReadableName() - if auxLog: - print >>auxLog, ("('ADDED', %r, %r)" % (b.getReadableName(), - b.getReportData())) - elif b is None: - print "REMOVED: %r" % a.getReadableName() - if auxLog: - print >>auxLog, ("('REMOVED', %r, %r)" % (a.getReadableName(), - a.getReportData())) - elif confidence: - print "CHANGED: %r to %r" % (a.getReadableName(), - b.getReadableName()) - if auxLog: - print >>auxLog, ("('CHANGED', %r, %r, %r, %r)" - % (a.getReadableName(), - b.getReadableName(), - a.getReportData(), - b.getReportData())) - else: - pass - - print "TOTAL REPORTS: %r" % len(resultsB.diagnostics) - if auxLog: - print >>auxLog, "('TOTAL', %r)" % len(resultsB.diagnostics) - -if __name__ == '__main__': - main() |