def getSymbolAnalysisFor(self, routineName, symbolAnalysis=None, symbolAnalysisByNameAndSource=None, call=None, analysisWarningsByCalleeName=None): if symbolAnalysis == None: symbolAnalysis = {} if symbolAnalysisByNameAndSource == None: symbolAnalysisByNameAndSource = {} if analysisWarningsByCalleeName == None: analysisWarningsByCalleeName = {} routine = self.routinesByName.get(routineName) if not routine: return symbolAnalysis, symbolAnalysisByNameAndSource routineArguments = getArguments(routine) callArguments = [] if call != None: callArguments = getArguments(call) if call.getAttribute("callee") != routineName: raise Exception( "call passed to analysis of %s is not a call to this routine: %s" % (routineName, prettyprint(call))) if len(callArguments) != len(routineArguments): warnings = analysisWarningsByCalleeName.get(routineName, []) warnings.append( (call.getAttribute("caller"), len(callArguments), len(routineArguments), str(callArguments))) analysisWarningsByCalleeName[routineName] = warnings return symbolAnalysis, symbolAnalysisByNameAndSource templates_and_entries = getDomainDependantTemplatesAndEntries( self.doc, routine) analysisToAdd = {} #check arguments to this routine - temporarily remove previous calls from the analysis. #we don't want to overwrite information from previous calls. temporarilyStoredAnalysisByArgumentName = {} for argIndex, _ in enumerate(callArguments): localArgumentName = routineArguments[argIndex] if not (routineName, localArgumentName) in symbolAnalysis: continue temporarilyStoredAnalysisByArgumentName[ localArgumentName] = symbolAnalysis[(routineName, localArgumentName)] del symbolAnalysis[(routineName, localArgumentName)] #Symbol Analysis based on local information for (_, entry) in templates_and_entries: analysis = SymbolAnalysis() analysis.name = entry.firstChild.nodeValue analysis.sourceModule = entry.getAttribute("sourceModule") analysis.sourceSymbol = entry.getAttribute("sourceSymbol") analysis.aliasNamesByRoutineName[routineName] = analysis.name argIndex = -1 try: argIndex = routineArguments.index(analysis.name) except Exception: pass if argIndex > -1: analysis.argumentIndexByRoutineName[routineName] = argIndex if argIndex > -1: analysis.symbolType = SymbolType.ARGUMENT_WITH_DOMAIN_DEPENDANT_SPEC elif type(analysis.sourceModule) in [ unicode, str ] and analysis.sourceModule != "": analysis.symbolType = SymbolType.MODULE_DATA_WITH_DOMAIN_DEPENDANT_SPEC else: analysis.symbolType = SymbolType.DOMAIN_DEPENDANT analysisToAdd[analysis.name] = analysis for argIndex, argument in enumerate(routineArguments): if argument in analysisToAdd: continue analysis = SymbolAnalysis() analysis.name = argument analysis.symbolType = SymbolType.ARGUMENT analysis.argumentIndexByRoutineName[routineName] = argIndex analysisToAdd[analysis.name] = analysis #Symbol Analysis based on caller #--> check whether an analysis has already been done, update that and add it under the current routine, symbolName tuple for symbolName in analysisToAdd.keys(): currentAnalysis = analysisToAdd[symbolName] argIndex = currentAnalysis.argumentIndexByRoutineName.get( routineName, -1) existingSymbolAnalysis = None if argIndex > -1 and len(callArguments) > 0: symbolNameInCaller = callArguments[argIndex] callerName = call.getAttribute("caller") existingSymbolAnalysis = symbolAnalysis.get( (callerName, symbolNameInCaller), []) elif currentAnalysis.isModuleSymbol: existingModuleSymbolAnalysis = symbolAnalysisByNameAndSource.get( (currentAnalysis.sourceSymbol, currentAnalysis.sourceModule)) if existingModuleSymbolAnalysis: existingSymbolAnalysis = [existingModuleSymbolAnalysis] else: existingSymbolAnalysis = [] else: existingSymbolAnalysis = [currentAnalysis] for analysis in existingSymbolAnalysis: if not isinstance(analysis, SymbolAnalysis): raise Exception( "unexpected error in routine %s: current analysis list contains unexpected objects: %s" % (routineName, str(existingSymbolAnalysis))) if len(existingSymbolAnalysis) == 0 or ( len(existingSymbolAnalysis) == 1 and existingSymbolAnalysis[0] == currentAnalysis): symbolAnalysis[(routineName, symbolName)] = [currentAnalysis] if currentAnalysis.isModuleSymbol: symbolAnalysisByNameAndSource[( currentAnalysis.sourceSymbol, currentAnalysis.sourceModule)] = currentAnalysis else: for analysis in existingSymbolAnalysis: analysis.updateWith(currentAnalysis, routineName) symbolAnalysis[(routineName, symbolName)] = existingSymbolAnalysis #Analyse callgraph downstream from here for call in self.callsByCallerName.get(routineName, []): if call.getAttribute("caller") != routineName: raise Exception( "unexpected error when constructing callgraph for symbol aliases" ) calleeName = call.getAttribute("callee") symbolAnalysis, symbolAnalysisByNameAndSource = self.getSymbolAnalysisFor( calleeName, symbolAnalysis=symbolAnalysis, symbolAnalysisByNameAndSource=symbolAnalysisByNameAndSource, call=call, analysisWarningsByCalleeName=analysisWarningsByCalleeName) for argumentName in temporarilyStoredAnalysisByArgumentName.keys(): symbolAnalysis[( routineName, argumentName)] = temporarilyStoredAnalysisByArgumentName[ argumentName] + symbolAnalysis.get( (routineName, argumentName), []) return symbolAnalysis, symbolAnalysisByNameAndSource
# ])) # ] + symbolRows #symbols )) #read in working xml srcFile = openFile(str(options.source), 'r') data = srcFile.read() srcFile.close() doc = parseString(data) analyzer = SymbolDependencyAnalyzer(doc) if options.debug: print "=== calls by calleename ===" prettyprint(analyzer.callsByCalleeName) print "=== calls by callsByCallerName ===" prettyprint(analyzer.callsByCallerName) print "=== callGraphEdgesByCallerName ===" prettyprint(analyzer.callGraphEdgesByCallerName) print "=== routines by name ===" prettyprint(analyzer.routinesByName) analysis = None if options.symbolGraphRootRoutine: analysis = analyzer.getSymbolAnalysisByRoutine( options.symbolGraphRootRoutine) elif options.allSymbols: analysis = analyzer.getSymbolAnalysisByRoutine() if options.debug and analysis != None: print "=== analysis ==="
def getSymbolAnalysisFor(self, routineName, symbolAnalysis=None, symbolAnalysisByNameAndSource=None, call=None, analysisWarningsByCalleeName=None): if symbolAnalysis == None: symbolAnalysis = {} if symbolAnalysisByNameAndSource == None: symbolAnalysisByNameAndSource = {} if analysisWarningsByCalleeName == None: analysisWarningsByCalleeName = {} routine = self.routinesByName.get(routineName) if not routine: return symbolAnalysis, symbolAnalysisByNameAndSource routineArguments = getArguments(routine) callArguments = [] if call != None: callArguments = getArguments(call) if call.getAttribute("callee") != routineName: raise Exception("call passed to analysis of %s is not a call to this routine: %s" %( routineName, prettyprint(call) )) if len(callArguments) != len(routineArguments): warnings = analysisWarningsByCalleeName.get(routineName, []) warnings.append((call.getAttribute("caller"), len(callArguments), len(routineArguments), str(callArguments))) analysisWarningsByCalleeName[routineName] = warnings return symbolAnalysis, symbolAnalysisByNameAndSource templates_and_entries = getDomainDependantTemplatesAndEntries( self.doc, routine ) analysisToAdd = {} #check arguments to this routine - temporarily remove previous calls from the analysis. #we don't want to overwrite information from previous calls. temporarilyStoredAnalysisByArgumentName = {} for argIndex, _ in enumerate(callArguments): localArgumentName = routineArguments[argIndex] if not (routineName, localArgumentName) in symbolAnalysis: continue temporarilyStoredAnalysisByArgumentName[localArgumentName] = symbolAnalysis[(routineName, localArgumentName)] del symbolAnalysis[(routineName, localArgumentName)] #Symbol Analysis based on local information for (_, entry) in templates_and_entries: analysis = SymbolAnalysis() analysis.name = entry.firstChild.nodeValue analysis.sourceModule = entry.getAttribute("sourceModule") analysis.sourceSymbol = entry.getAttribute("sourceSymbol") analysis.aliasNamesByRoutineName[routineName] = analysis.name argIndex = -1 try: argIndex = routineArguments.index(analysis.name) except Exception: pass if argIndex > -1: analysis.argumentIndexByRoutineName[routineName] = argIndex if argIndex > -1: analysis.symbolType = SymbolType.ARGUMENT_WITH_DOMAIN_DEPENDANT_SPEC elif type(analysis.sourceModule) in [unicode, str] and analysis.sourceModule != "": analysis.symbolType = SymbolType.MODULE_DATA_WITH_DOMAIN_DEPENDANT_SPEC else: analysis.symbolType = SymbolType.DOMAIN_DEPENDANT analysisToAdd[analysis.name] = analysis for argIndex, argument in enumerate(routineArguments): if argument in analysisToAdd: continue analysis = SymbolAnalysis() analysis.name = argument analysis.symbolType = SymbolType.ARGUMENT analysis.argumentIndexByRoutineName[routineName] = argIndex analysisToAdd[analysis.name] = analysis #Symbol Analysis based on caller #--> check whether an analysis has already been done, update that and add it under the current routine, symbolName tuple for symbolName in analysisToAdd.keys(): currentAnalysis = analysisToAdd[symbolName] argIndex = currentAnalysis.argumentIndexByRoutineName.get(routineName, -1) existingSymbolAnalysis = None if argIndex > -1 and len(callArguments) > 0: symbolNameInCaller = callArguments[argIndex] callerName = call.getAttribute("caller") existingSymbolAnalysis = symbolAnalysis.get((callerName, symbolNameInCaller), []) elif currentAnalysis.isModuleSymbol: existingModuleSymbolAnalysis = symbolAnalysisByNameAndSource.get((currentAnalysis.sourceSymbol, currentAnalysis.sourceModule)) if existingModuleSymbolAnalysis: existingSymbolAnalysis = [existingModuleSymbolAnalysis] else: existingSymbolAnalysis = [] else: existingSymbolAnalysis = [currentAnalysis] for analysis in existingSymbolAnalysis: if not isinstance(analysis, SymbolAnalysis): raise Exception("unexpected error in routine %s: current analysis list contains unexpected objects: %s" %( routineName, str(existingSymbolAnalysis) )) if len(existingSymbolAnalysis) == 0 or (len(existingSymbolAnalysis) == 1 and existingSymbolAnalysis[0] == currentAnalysis): symbolAnalysis[(routineName, symbolName)] = [currentAnalysis] if currentAnalysis.isModuleSymbol: symbolAnalysisByNameAndSource[(currentAnalysis.sourceSymbol, currentAnalysis.sourceModule)] = currentAnalysis else: for analysis in existingSymbolAnalysis: analysis.updateWith(currentAnalysis, routineName) symbolAnalysis[(routineName, symbolName)] = existingSymbolAnalysis #Analyse callgraph downstream from here for call in self.callsByCallerName.get(routineName, []): if call.getAttribute("caller") != routineName: raise Exception( "unexpected error when constructing callgraph for symbol aliases" ) calleeName = call.getAttribute("callee") symbolAnalysis, symbolAnalysisByNameAndSource = self.getSymbolAnalysisFor( calleeName, symbolAnalysis=symbolAnalysis, symbolAnalysisByNameAndSource=symbolAnalysisByNameAndSource, call=call, analysisWarningsByCalleeName=analysisWarningsByCalleeName ) for argumentName in temporarilyStoredAnalysisByArgumentName.keys(): symbolAnalysis[(routineName, argumentName)] = temporarilyStoredAnalysisByArgumentName[argumentName] + symbolAnalysis.get((routineName, argumentName), []) return symbolAnalysis, symbolAnalysisByNameAndSource
# ] + symbolRows # symbols ) ) # read in working xml srcFile = openFile(str(options.source), "r") data = srcFile.read() srcFile.close() doc = parseString(data) analyzer = SymbolDependencyAnalyzer(doc) if options.debug: print "=== calls by calleename ===" prettyprint(analyzer.callsByCalleeName) print "=== calls by callsByCallerName ===" prettyprint(analyzer.callsByCallerName) print "=== callGraphEdgesByCallerName ===" prettyprint(analyzer.callGraphEdgesByCallerName) print "=== routines by name ===" prettyprint(analyzer.routinesByName) analysis = None if options.symbolGraphRootRoutine: analysis = analyzer.getSymbolAnalysisByRoutine(options.symbolGraphRootRoutine) elif options.allSymbols: analysis = analyzer.getSymbolAnalysisByRoutine() if options.debug and analysis != None: print "=== analysis ===" prettyprint(analysis)