def __init__(self, mainFilePath, mainFunction, buildSolutionCmd, keepBackupFiles=False): ''' Constructor. ''' self.buildSolutionCmd = buildSolutionCmd self.keepBackupFiles = keepBackupFiles self.sourceCodeParser = SourceCodeParser( ProgramExecution.Languages.C_PLUS_PLUS, mainFilePath, mainFunction) self.filesToAnnotate = [] self.functionsToAnnotate = [] self.classesToAnnotate = [] self.mainFilePath = mainFilePath self.dumpFileName = "" self.oldFiles = []
def __init__(self, mainFilePath, mainFunction, buildSolutionCmd, keepBackupFiles = False): ''' Constructor. ''' self.buildSolutionCmd = buildSolutionCmd self.keepBackupFiles = keepBackupFiles self.sourceCodeParser = SourceCodeParser(ProgramExecution.Languages.C_PLUS_PLUS, mainFilePath, mainFunction) self.filesToAnnotate = [] self.functionsToAnnotate = [] self.classesToAnnotate = [] self.mainFilePath = mainFilePath self.dumpFileName = "" self.oldFiles = []
class CppAnnotator: ''' Annotator for C++ classes. It's the C++ counterpart of annotator.Annotator. As Annotator, it follows the "with" syntax (RAII idiom for Python): inside the "with" scope, the C++ functions are annotated to generate a call-graph database. This is the code flow to get this effect: * Create a CppAnnotator. * call annotateMainFile(): * this backs up the main file name, to be annotated later. * call annotateFunctions() or similar annotation functions: * this saves these functions in a container, to be annotated later. * with myCppAnnotator... this calls __enter__(), where: * annotations actually take place: * main file and functions from the containers are modified, saving a backup for each one of them. * build the compiler solution. This generates a new EXE. * call the EXE inside the with (for example, using os.system()). * this EXE will generate the annotations (remember the annotations and build above). * exit the with clause: * restore the backups for all the modified files. * "touch" the files, to force the compiler to build them. * build the solution. This generates an EXE without annotations. ''' activeAnnotators = False ## # @param self The CppAnnotator instance to construct. # @param mainFilePath The program's main file path. # @param mainFunction The program's main function. # @param buildSolutionCmd Command to build the solution. # @param keepBackupFiles Keep annotated files after restoring the original (at the __exit__() function). def __init__(self, mainFilePath, mainFunction, buildSolutionCmd, keepBackupFiles = False): ''' Constructor. ''' self.buildSolutionCmd = buildSolutionCmd self.keepBackupFiles = keepBackupFiles self.sourceCodeParser = SourceCodeParser(ProgramExecution.Languages.C_PLUS_PLUS, mainFilePath, mainFunction) self.filesToAnnotate = [] self.functionsToAnnotate = [] self.classesToAnnotate = [] self.mainFilePath = mainFilePath self.dumpFileName = "" self.oldFiles = [] # @param self The CppAnnotator instance. # @param dumpFileName File where the call graph database will be dumped. def annotateMainFile(self, dumpFileName ): ''' Mark main file to be annotated at __enter__(). ''' self.dumpFileName = dumpFileName ## # @param self The CppAnnotator instance. # @param originalFileName File name of the original (unprocessed) file name. # @param headerToInclude Header to include. def annotateFile(self, originalFileName, headerToInclude): ''' Mark a C++ source file to be annotated __enter__(). ''' self.filesToAnnotate.append((originalFileName, headerToInclude)) ## # @param self The CppAnnotator instance. # @param originalFileName File name of the original (unprocessed) file name. # @param headerToInclude Header to include. # @param functionNames Function names to filter. def annotateFunctions(self, originalFileName, headerToInclude, functionNames = []): ''' Mark a C++ source file to be annotated __enter__(), filtering by functions. ''' self.functionsToAnnotate.append((originalFileName, headerToInclude, functionNames)) ## # @param self The CppAnnotator instance. # @param originalFileName File name of the original (unprocessed) file name. # @param headerToInclude Header to include. # @param classNames Class names to filter. def annotateClasses(self, originalFileName, headerToInclude, classNames = []): ''' Mark a C++ source file to be annotated __enter__(), filtering by classes. ''' self.classesToAnnotate.append((originalFileName, headerToInclude, classNames)) ## # @param self The CppAnnotator instance. def __enter__(self): ''' Entry point for the "with" sentence. It annotates the files, and builds the solution. The new EXE will generate the Json database. ''' if CppAnnotator.activeAnnotators: #Limit instances number to 1 raise RuntimeError('Cpp annotators number should limit to 1.') CppAnnotator.activeAnnotators = True self._resetForNewAnnotations() try: #Backup main old file, in order to restore it later mainBackupFileName = getBackupFileName(self.mainFilePath) shutil.copyfile(self.mainFilePath, mainBackupFileName) self.oldFiles.append(self.mainFilePath) self.sourceCodeParser.annotateMainFile(self.dumpFileName) #Merge 3 containers in one, and iterate it originalFileNameToInfo = {} for myFile in self.filesToAnnotate: originalFileName, headerToInclude = myFile myInfo = [headerToInclude, None, None] originalFileNameToInfo[originalFileName] = myInfo for myClass in self.classesToAnnotate: originalFileName, headerToInclude, classNames = myClass if originalFileNameToInfo.has_key(originalFileName): myInfo = originalFileNameToInfo[originalFileName] else: myInfo = [headerToInclude, None, None] originalFileNameToInfo[originalFileName] = myInfo myInfo[1] = classNames for myFunction in self.functionsToAnnotate: originalFileName, headerToInclude, functionNames = tuple(myFunction) if originalFileNameToInfo.has_key(originalFileName): myInfo = originalFileNameToInfo[originalFileName] else: myInfo = [headerToInclude, None, None] originalFileNameToInfo[originalFileName] = myInfo myInfo[2] = functionNames for originalFileName, fileInfo in originalFileNameToInfo.items(): headerToInclude, classNames, functionNames = fileInfo #Backup old files, in order to restore them later backupFileName = getBackupFileName(originalFileName) shutil.copyfile(originalFileName, backupFileName) self.oldFiles.append(originalFileName) if classNames is None and functionNames is None: self.sourceCodeParser.annotateFile(backupFileName, originalFileName, headerToInclude) else: if classNames is not None: self.sourceCodeParser.annotateCppClasses(backupFileName, originalFileName, headerToInclude, classNames) if functionNames is not None and classNames is None: self.sourceCodeParser.annotateCppFunctions(backupFileName, originalFileName, headerToInclude, functionNames) self.buildSolution_() return self except Exception, e: print str(e) self.restoreSourcesForSolution_() raise e
class CppAnnotator: ''' Annotator for C++ classes. It's the C++ counterpart of annotator.Annotator. As Annotator, it follows the "with" syntax (RAII idiom for Python): inside the "with" scope, the C++ functions are annotated to generate a call-graph database. This is the code flow to get this effect: * Create a CppAnnotator. * call annotateMainFile(): * this backs up the main file name, to be annotated later. * call annotateFunctions() or similar annotation functions: * this saves these functions in a container, to be annotated later. * with myCppAnnotator... this calls __enter__(), where: * annotations actually take place: * main file and functions from the containers are modified, saving a backup for each one of them. * build the compiler solution. This generates a new EXE. * call the EXE inside the with (for example, using os.system()). * this EXE will generate the annotations (remember the annotations and build above). * exit the with clause: * restore the backups for all the modified files. * "touch" the files, to force the compiler to build them. * build the solution. This generates an EXE without annotations. ''' activeAnnotators = False ## # @param self The CppAnnotator instance to construct. # @param mainFilePath The program's main file path. # @param mainFunction The program's main function. # @param buildSolutionCmd Command to build the solution. # @param keepBackupFiles Keep annotated files after restoring the original (at the __exit__() function). def __init__(self, mainFilePath, mainFunction, buildSolutionCmd, keepBackupFiles=False): ''' Constructor. ''' self.buildSolutionCmd = buildSolutionCmd self.keepBackupFiles = keepBackupFiles self.sourceCodeParser = SourceCodeParser( ProgramExecution.Languages.C_PLUS_PLUS, mainFilePath, mainFunction) self.filesToAnnotate = [] self.functionsToAnnotate = [] self.classesToAnnotate = [] self.mainFilePath = mainFilePath self.dumpFileName = "" self.oldFiles = [] # @param self The CppAnnotator instance. # @param dumpFileName File where the call graph database will be dumped. def annotateMainFile(self, dumpFileName): ''' Mark main file to be annotated at __enter__(). ''' self.dumpFileName = dumpFileName ## # @param self The CppAnnotator instance. # @param originalFileName File name of the original (unprocessed) file name. # @param headerToInclude Header to include. def annotateFile(self, originalFileName, headerToInclude): ''' Mark a C++ source file to be annotated __enter__(). ''' self.filesToAnnotate.append((originalFileName, headerToInclude)) ## # @param self The CppAnnotator instance. # @param originalFileName File name of the original (unprocessed) file name. # @param headerToInclude Header to include. # @param functionNames Function names to filter. def annotateFunctions(self, originalFileName, headerToInclude, functionNames=[]): ''' Mark a C++ source file to be annotated __enter__(), filtering by functions. ''' self.functionsToAnnotate.append( (originalFileName, headerToInclude, functionNames)) ## # @param self The CppAnnotator instance. # @param originalFileName File name of the original (unprocessed) file name. # @param headerToInclude Header to include. # @param classNames Class names to filter. def annotateClasses(self, originalFileName, headerToInclude, classNames=[]): ''' Mark a C++ source file to be annotated __enter__(), filtering by classes. ''' self.classesToAnnotate.append( (originalFileName, headerToInclude, classNames)) ## # @param self The CppAnnotator instance. def __enter__(self): ''' Entry point for the "with" sentence. It annotates the files, and builds the solution. The new EXE will generate the Json database. ''' if CppAnnotator.activeAnnotators: #Limit instances number to 1 raise RuntimeError('Cpp annotators number should limit to 1.') CppAnnotator.activeAnnotators = True self._resetForNewAnnotations() try: #Backup main old file, in order to restore it later mainBackupFileName = getBackupFileName(self.mainFilePath) shutil.copyfile(self.mainFilePath, mainBackupFileName) self.oldFiles.append(self.mainFilePath) self.sourceCodeParser.annotateMainFile(self.dumpFileName) #Merge 3 containers in one, and iterate it originalFileNameToInfo = {} for myFile in self.filesToAnnotate: originalFileName, headerToInclude = myFile myInfo = [headerToInclude, None, None] originalFileNameToInfo[originalFileName] = myInfo for myClass in self.classesToAnnotate: originalFileName, headerToInclude, classNames = myClass if originalFileNameToInfo.has_key(originalFileName): myInfo = originalFileNameToInfo[originalFileName] else: myInfo = [headerToInclude, None, None] originalFileNameToInfo[originalFileName] = myInfo myInfo[1] = classNames for myFunction in self.functionsToAnnotate: originalFileName, headerToInclude, functionNames = tuple( myFunction) if originalFileNameToInfo.has_key(originalFileName): myInfo = originalFileNameToInfo[originalFileName] else: myInfo = [headerToInclude, None, None] originalFileNameToInfo[originalFileName] = myInfo myInfo[2] = functionNames for originalFileName, fileInfo in originalFileNameToInfo.items(): headerToInclude, classNames, functionNames = fileInfo #Backup old files, in order to restore them later backupFileName = getBackupFileName(originalFileName) shutil.copyfile(originalFileName, backupFileName) self.oldFiles.append(originalFileName) if classNames is None and functionNames is None: self.sourceCodeParser.annotateFile(backupFileName, originalFileName, headerToInclude) else: if classNames is not None: self.sourceCodeParser.annotateCppClasses( backupFileName, originalFileName, headerToInclude, classNames) if functionNames is not None and classNames is None: self.sourceCodeParser.annotateCppFunctions( backupFileName, originalFileName, headerToInclude, functionNames) self.buildSolution_() return self except Exception, e: print str(e) self.restoreSourcesForSolution_() raise e