[analyzer] Make CmpRuns external-user friendly.
CmpRuns can be used for static analyzer bug report comparison. However, we want to make sure external users do not rely on the way bugs are represented (plist files). Make sure that we have a user friendly/documented API for CmpRuns script. llvm-svn: 160314
This commit is contained in:
parent
42bff962b6
commit
9b7d7140ef
|
@ -11,12 +11,63 @@ two perspectives:
|
|||
|
||||
2. For use by end users who want to integrate regular static analyzer testing
|
||||
into a buildbot like environment.
|
||||
|
||||
Usage:
|
||||
|
||||
# Load the results of both runs, to obtain lists of the corresponding
|
||||
# AnalysisDiagnostic objects.
|
||||
resultsA = loadResults(dirA, opts, deleteEmpty)
|
||||
resultsB = loadResults(dirB, opts, deleteEmpty)
|
||||
|
||||
# Generate a relation from diagnostics in run A to diagnostics in run B
|
||||
# to obtain a list of triples (a, b, confidence).
|
||||
diff = compareResults(resultsA, resultsB)
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import plistlib
|
||||
|
||||
#
|
||||
class AnalysisDiagnostic:
|
||||
def __init__(self, data, report, htmlReport):
|
||||
self._data = data
|
||||
self._loc = self._data['location']
|
||||
self._report = report
|
||||
self._htmlReport = htmlReport
|
||||
|
||||
def getFileName(self):
|
||||
return self._report.run.getSourceName(self._report.files[self._loc['file']])
|
||||
|
||||
def getLine(self):
|
||||
return self._loc['line']
|
||||
|
||||
def getColumn(self):
|
||||
return self._loc['col']
|
||||
|
||||
def getCategory(self):
|
||||
return self._data['category']
|
||||
|
||||
def getDescription(self):
|
||||
return self._data['description']
|
||||
|
||||
def getIssueIdentifier(self) :
|
||||
id = ''
|
||||
if 'issue_context' in self._data :
|
||||
id += self._data['issue_context']
|
||||
if 'issue_hash' in self._data :
|
||||
id += str(self._data['issue_hash'])
|
||||
return id
|
||||
|
||||
def getReport(self):
|
||||
if self._htmlReport is None:
|
||||
return " "
|
||||
return os.path.join(self._report.run.path, self._htmlReport)
|
||||
|
||||
def getReadableName(self):
|
||||
return '%s:%d:%d, %s: %s' % (self.getFileName(), self.getLine(),
|
||||
self.getColumn(), self.getCategory(),
|
||||
self.getDescription())
|
||||
|
||||
class multidict:
|
||||
def __init__(self, elts=()):
|
||||
|
@ -54,34 +105,6 @@ class AnalysisReport:
|
|||
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']
|
||||
category = self.data['category']
|
||||
description = self.data['description']
|
||||
|
||||
# FIXME: Get a report number based on this key, to 'distinguish'
|
||||
# reports, or something.
|
||||
|
||||
return '%s:%d:%d, %s: %s' % (filename, line, column, category,
|
||||
description)
|
||||
|
||||
def getReportData(self):
|
||||
if self.htmlReport is None:
|
||||
return " "
|
||||
return os.path.join(self.report.run.path, self.htmlReport)
|
||||
# We could also dump the report with:
|
||||
# return open(os.path.join(self.report.run.path,
|
||||
# self.htmlReport), "rb").read()
|
||||
|
||||
class AnalysisRun:
|
||||
def __init__(self, path, opts):
|
||||
self.path = path
|
||||
|
@ -134,13 +157,8 @@ def loadResults(path, opts, deleteEmpty=True):
|
|||
|
||||
return run
|
||||
|
||||
def getIssueIdentifier(d) :
|
||||
id = ''
|
||||
if 'issue_context' in d.data :
|
||||
id += d.data['issue_context']
|
||||
if 'issue_hash' in d.data :
|
||||
id += str(d.data['issue_hash'])
|
||||
return id
|
||||
def cmpAnalysisDiagnostic(d) :
|
||||
return d.getIssueIdentifier()
|
||||
|
||||
def compareResults(A, B):
|
||||
"""
|
||||
|
@ -160,14 +178,14 @@ def compareResults(A, B):
|
|||
neqB = []
|
||||
eltsA = list(A.diagnostics)
|
||||
eltsB = list(B.diagnostics)
|
||||
eltsA.sort(key = getIssueIdentifier)
|
||||
eltsB.sort(key = getIssueIdentifier)
|
||||
eltsA.sort(key = cmpAnalysisDiagnostic)
|
||||
eltsB.sort(key = cmpAnalysisDiagnostic)
|
||||
while eltsA and eltsB:
|
||||
a = eltsA.pop()
|
||||
b = eltsB.pop()
|
||||
if (getIssueIdentifier(a) == getIssueIdentifier(b)) :
|
||||
if (a.getIssueIdentifier() == b.getIssueIdentifier()) :
|
||||
res.append((a, b, 0))
|
||||
elif a.data > b.data:
|
||||
elif a._data > b._data:
|
||||
neqA.append(a)
|
||||
eltsB.append(b)
|
||||
else:
|
||||
|
@ -189,7 +207,7 @@ def compareResults(A, B):
|
|||
|
||||
return res
|
||||
|
||||
def cmpScanBuildResults(dirA, dirB, opts, deleteEmpty=True):
|
||||
def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True):
|
||||
# Load the run results.
|
||||
resultsA = loadResults(dirA, opts, deleteEmpty)
|
||||
resultsB = loadResults(dirB, opts, deleteEmpty)
|
||||
|
@ -209,13 +227,13 @@ def cmpScanBuildResults(dirA, dirB, opts, deleteEmpty=True):
|
|||
foundDiffs += 1
|
||||
if auxLog:
|
||||
print >>auxLog, ("('ADDED', %r, %r)" % (b.getReadableName(),
|
||||
b.getReportData()))
|
||||
b.getReport()))
|
||||
elif b is None:
|
||||
print "REMOVED: %r" % a.getReadableName()
|
||||
foundDiffs += 1
|
||||
if auxLog:
|
||||
print >>auxLog, ("('REMOVED', %r, %r)" % (a.getReadableName(),
|
||||
a.getReportData()))
|
||||
a.getReport()))
|
||||
elif confidence:
|
||||
print "CHANGED: %r to %r" % (a.getReadableName(),
|
||||
b.getReadableName())
|
||||
|
@ -224,8 +242,8 @@ def cmpScanBuildResults(dirA, dirB, opts, deleteEmpty=True):
|
|||
print >>auxLog, ("('CHANGED', %r, %r, %r, %r)"
|
||||
% (a.getReadableName(),
|
||||
b.getReadableName(),
|
||||
a.getReportData(),
|
||||
b.getReportData()))
|
||||
a.getReport(),
|
||||
b.getReport()))
|
||||
else:
|
||||
pass
|
||||
|
||||
|
|
|
@ -357,7 +357,7 @@ def runCmpResults(Dir):
|
|||
OLD_STDOUT = sys.stdout
|
||||
sys.stdout = Discarder()
|
||||
# Scan the results, delete empty plist files.
|
||||
NumDiffs = CmpRuns.cmpScanBuildResults(RefDir, NewDir, Opts, False)
|
||||
NumDiffs = CmpRuns.dumpScanBuildResultsDiff(RefDir, NewDir, Opts, False)
|
||||
sys.stdout = OLD_STDOUT
|
||||
if (NumDiffs > 0) :
|
||||
print "Warning: %r differences in diagnostics. See %s" % \
|
||||
|
|
Loading…
Reference in New Issue