From 45518b1f768c302837096d1359b2935cdb8ee08d Mon Sep 17 00:00:00 2001 From: Anna Zaks Date: Sat, 5 Nov 2011 05:20:48 +0000 Subject: [PATCH] [analyzer] Add support for testing with individual preprocessed files. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143786 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/analyzer/SATestAdd.py | 16 ++-- utils/analyzer/SATestBuild.py | 151 +++++++++++++++++++++++++++------- 2 files changed, 133 insertions(+), 34 deletions(-) mode change 100644 => 100755 utils/analyzer/SATestAdd.py mode change 100644 => 100755 utils/analyzer/SATestBuild.py diff --git a/utils/analyzer/SATestAdd.py b/utils/analyzer/SATestAdd.py old mode 100644 new mode 100755 index 9fab07bfa9..ea3ec21d64 --- a/utils/analyzer/SATestAdd.py +++ b/utils/analyzer/SATestAdd.py @@ -26,7 +26,7 @@ import sys # Params: # Dir is the directory where the sources are. # ID is a short string used to identify a project. -def addNewProject(ID) : +def addNewProject(ID, IsScanBuild) : CurDir = os.path.abspath(os.curdir) Dir = SATestBuild.getProjectDir(ID) if not os.path.exists(Dir): @@ -34,7 +34,7 @@ def addNewProject(ID) : sys.exit(-1) # Build the project. - SATestBuild.testProject(ID, True, Dir) + SATestBuild.testProject(ID, True, IsScanBuild, Dir) # Add the project ID to the project map. ProjectMapPath = os.path.join(CurDir, SATestBuild.ProjectMapFile) @@ -53,7 +53,7 @@ def addNewProject(ID) : sys.exit(-1) PMapWriter = csv.writer(PMapFile) - PMapWriter.writerow( (ID, Dir) ); + PMapWriter.writerow( (ID, int(IsScanBuild)) ); finally: PMapFile.close() @@ -65,7 +65,13 @@ def addNewProject(ID) : if __name__ == '__main__': if len(sys.argv) < 2: print >> sys.stderr, 'Usage: ', sys.argv[0],\ - '[project ID]' + 'project_ID ' \ + 'mode - 0 for single file project; 1 for scan_build' sys.exit(-1) + + IsScanBuild = 1 + if (len(sys.argv) >= 3): + IsScanBuild = int(sys.argv[2]) + assert((IsScanBuild == 0) | (IsScanBuild == 1)) - addNewProject(sys.argv[1]) + addNewProject(sys.argv[1], IsScanBuild) diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py old mode 100644 new mode 100755 index e6527eedc5..d15ca9186c --- a/utils/analyzer/SATestBuild.py +++ b/utils/analyzer/SATestBuild.py @@ -45,7 +45,7 @@ import glob import shutil import time import plistlib -from subprocess import check_call +from subprocess import check_call, CalledProcessError # Project map stores info about all the "registered" projects. ProjectMapFile = "projectMap.csv" @@ -57,6 +57,7 @@ CleanupScript = "cleanup_run_static_analyzer.sh" BuildScript = "run_static_analyzer.cmd" # The log file name. +LogFolderName = "Logs" BuildLogName = "run_static_analyzer.log" # Summary file - contains the summary of the failures. Ex: This info can be be # displayed when buildbot detects a build failure. @@ -71,6 +72,8 @@ SBOutputDirReferencePrefix = "Ref" Verbose = 1 +IsReferenceBuild = False + def getProjectMapPath(): ProjectMapPath = os.path.join(os.path.abspath(os.curdir), ProjectMapFile) @@ -83,6 +86,12 @@ def getProjectMapPath(): def getProjectDir(ID): return os.path.join(os.path.abspath(os.curdir), ID) +def getSBOutputDirName() : + if IsReferenceBuild == True : + return SBOutputDirReferencePrefix + SBOutputDirName + else : + return SBOutputDirName + # Run pre-processing script if any. def runCleanupScript(Dir, PBuildLogFile): ScriptPath = os.path.join(Dir, CleanupScript) @@ -124,36 +133,105 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile): except: print "Error: scan-build failed. See ",PBuildLogFile.name,\ " for details." - sys.exit(-1) + raise + +def hasNoExtension(FileName): + (Root, Ext) = os.path.splitext(FileName) + if ((Ext == "")) : + return True + return False -def buildProject(Dir, SBOutputDir, ClenupAfterBuild): +def isValidSingleInputFile(FileName): + (Root, Ext) = os.path.splitext(FileName) + if ((Ext == ".i") | (Ext == ".ii") | + (Ext == ".c") | (Ext == ".cpp") | + (Ext == ".m") | (Ext == "")) : + return True + return False + +# Run analysis on a set of preprocessed files. +def runAnalyzePreprocessed(Dir, SBOutputDir): + if os.path.exists(os.path.join(Dir, BuildScript)): + print "Error: The preprocessed files project should not contain %s" % \ + BuildScript + raise Exception() + + CmdPrefix = "clang -cc1 -analyze -analyzer-output=plist -w " + CmdPrefix += "-analyzer-checker=core " + + PlistPath = os.path.join(Dir, SBOutputDir, "date") + FailPath = os.path.join(PlistPath, "failures"); + os.makedirs(FailPath); + + for FullFileName in glob.glob(Dir + "/*"): + FileName = os.path.basename(FullFileName) + Failed = False + + # Only run the analyzes on supported files. + if (hasNoExtension(FileName)): + continue + if (isValidSingleInputFile(FileName) == False): + print "Error: Invalid single input file %s." % (FullFileName,) + raise Exception() + + # Build and call the analyzer command. + OutputOption = "-o " + os.path.join(PlistPath, FileName) + ".plist " + Command = CmdPrefix + OutputOption + os.path.join(Dir, FileName) + LogFile = open(os.path.join(FailPath, FileName + ".stderr.txt"), "w+b") + try: + if Verbose == 1: + print " Executing: %s" % (Command,) + check_call(Command, cwd = Dir, stderr=LogFile, + stdout=LogFile, + shell=True) + except CalledProcessError, e: + print "Error: Analyzes of %s failed. See %s for details." \ + "Error code %d." % \ + (FullFileName, LogFile.name, e.returncode) + Failed = True + finally: + LogFile.close() + + # If command did not fail, erase the log file. + if Failed == False: + os.remove(LogFile.name); + +def buildProject(Dir, SBOutputDir, IsScanBuild): TBegin = time.time() - BuildLogPath = os.path.join(Dir, BuildLogName) + BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName) print "Log file: %s" % (BuildLogPath,) - + print "Output directory: %s" %(SBOutputDir, ) + # Clean up the log file. if (os.path.exists(BuildLogPath)) : RmCommand = "rm " + BuildLogPath if Verbose == 1: print " Executing: %s" % (RmCommand,) check_call(RmCommand, shell=True) + + # Clean up scan build results. + if (os.path.exists(SBOutputDir)) : + RmCommand = "rm -r " + SBOutputDir + if Verbose == 1: + print " Executing: %s" % (RmCommand,) + check_call(RmCommand, shell=True) + assert(not os.path.exists(SBOutputDir)) + os.makedirs(os.path.join(SBOutputDir, LogFolderName)) # Open the log file. PBuildLogFile = open(BuildLogPath, "wb+") - try: - # Clean up scan build results. - if (os.path.exists(SBOutputDir)) : - RmCommand = "rm -r " + SBOutputDir - if Verbose == 1: - print " Executing: %s" % (RmCommand,) - check_call(RmCommand, stderr=PBuildLogFile, - stdout=PBuildLogFile, shell=True) + # Build and analyze the project. + try: runCleanupScript(Dir, PBuildLogFile) - runScanBuild(Dir, SBOutputDir, PBuildLogFile) - if ClenupAfterBuild : + if IsScanBuild: + runScanBuild(Dir, SBOutputDir, PBuildLogFile) + else: + runAnalyzePreprocessed(Dir, SBOutputDir) + + if IsReferenceBuild : runCleanupScript(Dir, PBuildLogFile) finally: @@ -189,9 +267,9 @@ def checkBuild(SBOutputDir): return; # Create summary file to display when the build fails. - SummaryPath = os.path.join(SBOutputDir, FailuresSummaryFileName); + SummaryPath = os.path.join(SBOutputDir, LogFolderName, FailuresSummaryFileName) if (Verbose > 0): - print " Creating the failures summary file %s." % (SummaryPath,) + print " Creating the failures summary file %s" % (SummaryPath,) SummaryLog = open(SummaryPath, "w+") try: @@ -216,7 +294,7 @@ def checkBuild(SBOutputDir): finally: SummaryLog.close() - print "Error: Scan-build failed. See ", \ + print "Error: analysis failed. See ", \ os.path.join(SBOutputDir, FailuresSummaryFileName) sys.exit(-1) @@ -235,6 +313,11 @@ def runCmpResults(Dir): # We have to go one level down the directory tree. RefList = glob.glob(RefDir + "/*") NewList = glob.glob(NewDir + "/*") + + # Log folders are also located in the results dir, so ignore them. + RefList.remove(os.path.join(RefDir, LogFolderName)) + NewList.remove(os.path.join(NewDir, LogFolderName)) + if len(RefList) == 0 or len(NewList) == 0: return False assert(len(RefList) == len(NewList)) @@ -271,8 +354,13 @@ def runCmpResults(Dir): print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin) return HaveDiffs + +def testProject(ID, InIsReferenceBuild, IsScanBuild , Dir=None): + global IsReferenceBuild + IsReferenceBuild = InIsReferenceBuild + + print " \n\n--- Building project %s" % (ID,) -def testProject(ID, IsReferenceBuild, Dir=None): TBegin = time.time() if Dir is None : @@ -281,13 +369,9 @@ def testProject(ID, IsReferenceBuild, Dir=None): print " Build directory: %s." % (Dir,) # Set the build results directory. - if IsReferenceBuild == True : - SBOutputDir = os.path.join(Dir, SBOutputDirReferencePrefix + \ - SBOutputDirName) - else : - SBOutputDir = os.path.join(Dir, SBOutputDirName) - - buildProject(Dir, SBOutputDir, IsReferenceBuild) + SBOutputDir = os.path.join(Dir, getSBOutputDirName()) + + buildProject(Dir, SBOutputDir, IsScanBuild) checkBuild(SBOutputDir) @@ -297,13 +381,22 @@ def testProject(ID, IsReferenceBuild, Dir=None): print "Completed tests for project %s (time: %.2f)." % \ (ID, (time.time()-TBegin)) -def testAll(IsReferenceBuild=False): +def testAll(InIsReferenceBuild = False): + PMapFile = open(getProjectMapPath(), "rb") try: PMapReader = csv.reader(PMapFile) for I in PMapReader: - print " --- Building project %s" % (I[0],) - testProject(I[0], IsReferenceBuild) + if (len(I) != 2) : + print "Error: Rows in the ProjectMapFile should have 3 entries." + raise Exception() + if (not ((I[1] == "1") | (I[1] == "0"))): + print "Error: Second entry in the ProjectMapFile should be 0 or 1." + raise Exception() + testProject(I[0], InIsReferenceBuild, int(I[1])) + except: + print "Error occurred. Premature termination." + raise finally: PMapFile.close() -- 2.40.0