]> granicus.if.org Git - clang/commitdiff
[analyzer] Make CmpRuns external-user friendly.
authorAnna Zaks <ganna@apple.com>
Mon, 16 Jul 2012 20:21:42 +0000 (20:21 +0000)
committerAnna Zaks <ganna@apple.com>
Mon, 16 Jul 2012 20:21:42 +0000 (20:21 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160314 91177308-0d34-0410-b5e6-96231b3b80d8

utils/analyzer/CmpRuns.py
utils/analyzer/SATestBuild.py

index 220045319facf67eacaa64a6c434a8dc829630aa..60133453485f17536444e2074243f36b9b240473 100755 (executable)
@@ -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
 
index 4b9d2eb60c838e725885078032d8c721dcf86375..93a3a72676804fb0a0f20d1428db3925cd3d642c 100755 (executable)
@@ -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" % \