public async Task <CallGraph <MethodDescriptor, LocationDescriptor> > GenerateCallGraphAsync() { Logger.LogS("SolutionAnalyzer", "GenerateCallGraphAsync", "Start building CG"); var callgraph = new CallGraph <MethodDescriptor, LocationDescriptor>(); var roots = await this.SolutionManager.GetRootsAsync(this.RootKind); var worklist = new Queue <MethodDescriptor>(roots); var visited = new HashSet <MethodDescriptor>(); callgraph.AddRootMethods(roots); while (worklist.Count > 0) { var currentMethodDescriptor = worklist.Dequeue(); visited.Add(currentMethodDescriptor); Logger.LogS("SolutionAnalyzer", "GenerateCallGraphAsync", "Proccesing {0}", currentMethodDescriptor); var methodEntity = await this.SolutionManager.GetMethodEntityAsync(currentMethodDescriptor); var calleesInfoForMethod = await methodEntity.GetCalleesInfoAsync(); foreach (var entry in calleesInfoForMethod) { var analysisNode = entry.Key; var callees = entry.Value; foreach (var calleeDescriptor in callees) { Logger.LogS("SolutionAnalyzer", "GenerateCallGraphAsync", "Adding {0}-{1} to CG", currentMethodDescriptor, calleeDescriptor); callgraph.AddCallAtLocation(analysisNode.LocationDescriptor, currentMethodDescriptor, calleeDescriptor); if (!visited.Contains(calleeDescriptor) && !worklist.Contains(calleeDescriptor)) { worklist.Enqueue(calleeDescriptor); } } } } return(callgraph); }
/* private ProjectMethod FindMethodSymbolAndProjectInSolution(MethodDescriptor methodDescriptor, CallGraph<MethodDescriptor, ALocation> callgraph) { return RoslynSymbolFactory.FindMethodSymbolAndProjectInSolution(this.Solution, methodDescriptor); } #region Just a test to discard about programation of a deletion o a croncrete type internal void RemoveTypesFromNode(MethodDescriptor methodDescriptor, string text) { var m = RoslynSymbolFactory.FindMethodSymbolInSolution(this.Solution, methodDescriptor); var am = new AMethod(m); var entityProcessor = (MethodEntityProcessor<ANode, AType, AMethod>) this.Dispatcher.GetEntityWithProcessor(EntityFactory<AMethod>.Create(am)); var entity = entityProcessor.MethodEntity; var pg = entity.PropGraph; ANode n = pg.FindNodeInPropationGraph(text); var statementProcessor = new StatementProcessor<ANode, AType, AMethod>(am, entity.ReturnVariable, entity.ThisRef, entity.ParameterNodes, pg); statementProcessor.RegisterRemoveNewExpressionAssignment(n); // entity.RemoveCallees(); entityProcessor.DoDelete(); //entity.InvalidateCaches(); } internal void RemoveAsignment(MethodDescriptor methodDescriptor, string p1, string p2) { var roslynMethod = RoslynSymbolFactory.FindMethodSymbolInSolution(this.Solution, methodDescriptor); var aMethod = new AMethod(roslynMethod); var entityProcessor = this.Dispatcher.GetEntityWithProcessor( EntityFactory<AMethod>.Create(aMethod)) as MethodEntityProcessor<ANode, AType, AMethod>; var entity = entityProcessor.MethodEntity; var syntaxNode = Utils.FindMethodDeclaration(aMethod); var nodes = syntaxNode.DescendantNodes().OfType<AssignmentExpressionSyntax>(); var node = nodes.First(a => a.Left.ToString() == p1 && a.Right.ToString() == p2); ANode lhs = entity.PropGraph.FindNodeInPropationGraph(p1); ANode rhs = entity.PropGraph.FindNodeInPropationGraph(p2); var statementProcessor = new StatementProcessor<ANode, AType, AMethod>(aMethod, entity.ReturnVariable, entity.ThisRef, entity.ParameterNodes, entity.PropGraph); statementProcessor.RegisterRemoveAssignment(lhs, rhs); entityProcessor.DoDelete(); //entity.InvalidateCaches(); } /// <summary> /// A test of how we should proceed when a method is modified /// </summary> /// <param name="methodDescriptor"></param> /// <param name="newCode"></param> internal void UpdateMethod(MethodDescriptor methodDescriptor, string newCode, CallGraph<MethodDescriptor, ALocation> callgraph) { // Find the method and project of the method to be updated var projectMethdod = FindMethodSymbolAndProjectInSolution(methodDescriptor, callgraph); var oldRoslynMethod = projectMethdod.Method; var project = projectMethdod.Project; var aMethod = new AMethod(oldRoslynMethod); //entityProcessor.MethodEntity.Save(roslynMethod.ContainingType.Name + "_" + roslynMethod.Name + "_orig.dot"); //-------------------------------------------------------------------------------------------------------- // This is to mimic a change in the method. We need to create a new comp var methodDecSyntax = Utils.FindMethodDeclaration(aMethod); var newMethodBody = SyntaxFactory.ParseStatement(newCode) as BlockSyntax; // here we update the method body var newMethodSyntax = methodDecSyntax.WithBody(newMethodBody); // This is a trick to recover the part of the syntax tree after replacing the project syntax tree var annotation = new SyntaxAnnotation("Hi"); newMethodSyntax = newMethodSyntax.WithAdditionalAnnotations(annotation); // update the syntax tree var oldRoot = methodDecSyntax.SyntaxTree.GetRoot(); var newRoot = oldRoot.ReplaceNode(methodDecSyntax, newMethodSyntax); // Compute the new compilation and semantic model var oldCompilation = project.GetCompilationAsync().Result; var newCompilation = oldCompilation.ReplaceSyntaxTree(oldRoot.SyntaxTree, newRoot.SyntaxTree); var newSemanticModel = newCompilation.GetSemanticModel(newRoot.SyntaxTree); // Recover the method node var recoveredMethodNode = newRoot.GetAnnotatedNodes(annotation).Single(); ////////////////////////////////////////////////////// // Get the entity corresponding to the new (updated) method var updatedRoslynMethod = newSemanticModel.GetDeclaredSymbol(recoveredMethodNode) as IMethodSymbol; PerformUpdate(oldRoslynMethod, newSemanticModel, updatedRoslynMethod); } public void PerformUpdate(IMethodSymbol oldRoslynMethod, SemanticModel newSemanticModel, IMethodSymbol newRoslynMethod) { var aMethod = new AMethod(oldRoslynMethod); // Get the entity and processor var entityDescriptor = EntityFactory<AMethod>.Create(aMethod); var entityProcessor = this.Dispatcher.GetEntityWithProcessor(entityDescriptor) as MethodEntityProcessor<ANode, AType, AMethod>; var oldMethodEntity = entityProcessor.MethodEntity; var syntaxProcessor = new MethodSyntaxProcessor(newRoslynMethod, newSemanticModel, Dispatcher); var newEntity = syntaxProcessor.ParseMethod() as MethodEntity<ANode, AType, AMethod>; // I propagate the removal of the node that represent the input parameters of the callees // This is to simulate the deletion of the method. // Do I need to do this? var propGraphOld = oldMethodEntity.PropGraph; var invoOld = GetInvocations(propGraphOld); foreach (var invocation in invoOld) { foreach (var aCallee in invocation.ComputeCalleesForNode(propGraphOld)) { RemoveCall(aCallee,invocation); } } // This is to force the callers to call me //foreach(var callerConext in entity.Callers) //{ // var caller = callerConext.Caller; // var callerEntityProcessor = Dispatcher.GetEntityWithProcessor(new MethodEntityDescriptor<AMethod>(caller)); // callerEntityProcessor.DoAnalysis(); //} // Here we propagate the removal of the retvalue of the method we eliminate if (oldMethodEntity.ReturnVariable != null) { var returnTypes = oldMethodEntity.GetTypes(oldMethodEntity.ReturnVariable); foreach (var callersContext in oldMethodEntity.Callers) { RemoveReturnValuesFromCallerLHS(returnTypes, callersContext.Caller, callersContext.CallLHS); } } this.Dispatcher.RegisterEntity(entityDescriptor, newEntity); // I get an entity processor to analyze the new entity var newEntityProcessor = Dispatcher.GetEntityWithProcessor(entityDescriptor) as MethodEntityProcessor<ANode, AType, AMethod>; /// I need to copy all the input data from the old method newEntity.CopyInterfaceDataAndCallers(oldMethodEntity); newEntityProcessor.DoAnalysis(); var propGraphNew = newEntity.PropGraph; var invoNew = GetInvocations(propGraphNew); //newEntityProcessor.MethodEntity.Save(oldRoslynMethod.ContainingType.Name + "_" + oldRoslynMethod.Name + "_d.dot"); oldMethodEntity.InvalidateCaches(); } private void RemoveReturnValuesFromCallerLHS(ISet<AType> returnTypes, AMethod aCaller, ANode lhs) { var entityProcessorforCaller = (MethodEntityProcessor<ANode, AType, AMethod>) Dispatcher.GetEntityWithProcessor(EntityFactory<AMethod>.Create((AMethod)aCaller)); var callerEntity = entityProcessorforCaller.MethodEntity; var statementProcessor = new StatementProcessor<ANode, AType, AMethod>((AMethod)aCaller, callerEntity.ReturnVariable, callerEntity.ThisRef, callerEntity.ParameterNodes, callerEntity.PropGraph); //callerEntity.PropGraph. statementProcessor.RegisterRemoveTypes(lhs, returnTypes); //callerEntity.InvalidateCaches(); entityProcessorforCaller.DoDelete(); } private void RemoveCall(AMethod aCallee, AInvocationExp<AMethod,AType,ANode> invocation) { var entityProcessorforCallee = Dispatcher.GetEntityWithProcessor(EntityFactory<AMethod>.Create((AMethod)aCallee)) as MethodEntityProcessor<ANode, AType, AMethod>; var calleeEntity = entityProcessorforCallee.MethodEntity; calleeEntity.InvalidateCaches(); // Delete progragation of arguments and receiver var statementProcessor = new StatementProcessor<ANode, AType, AMethod>((AMethod)aCallee, calleeEntity.ReturnVariable, calleeEntity.ThisRef, calleeEntity.ParameterNodes, calleeEntity.PropGraph); foreach (var p in calleeEntity.ParameterNodes) { statementProcessor.RegisterRemoveNewExpressionAssignment(p); } if (calleeEntity.ThisRef != null) statementProcessor.RegisterRemoveNewExpressionAssignment(calleeEntity.ThisRef); // entity.RemoveCallees(); entityProcessorforCallee.DoDelete(); var context = new CallConext<AMethod, ANode>(invocation.Caller,invocation.LHS,invocation.CallNode); calleeEntity.RemoveFromCallers(context); } private static List<AInvocationExp<AMethod, AType, ANode>> GetInvocations(PropagationGraph<ANode, AType, AMethod> propGraphOld) { var invoList = new List<AInvocationExp<AMethod, AType, ANode>>(); foreach (var oldCall in propGraphOld.CallNodes) { var oldCallInfo = propGraphOld.GetInvocationInfo(oldCall); invoList.Add(oldCallInfo); } return invoList; } #endregion */ #region Callgraph private static void UpdateCallGraph(IEntityProcessor entityProcessor, CallGraph<MethodDescriptor, LocationDescriptor> callgraph, Solution solution) { Contract.Assert(entityProcessor != null); var methodEntity = (MethodEntity)entityProcessor.Entity; Contract.Assert(methodEntity.MethodDescriptor != null); var callerMethod = methodEntity.MethodDescriptor; var pair = ProjectCodeProvider.GetProjectProviderAndSyntaxAsync(callerMethod, solution).Result; if (pair != null) { var codeProvider = pair.Item1; // Hack var methodEntityProcessor = new MethodEntityProcessor(methodEntity, ((MethodEntityProcessor)entityProcessor).dispatcher, codeProvider); //(MethodEntityProcessor)entityProcessor; var callSitesForMethod = methodEntityProcessor.GetCalleesInfo(); foreach (var callSiteNode in callSitesForMethod.Keys) { foreach (var calleeAMethod in callSitesForMethod[callSiteNode]) { //var callee = Utils.FindMethodSymbolDeclaration(this.Solution, ((AMethod)calleeAMethod).RoslynMethod); var callee = calleeAMethod; Logger.Instance.Log("SolutionAnalyzer", "UpdateCallGraph", "\t-> {0}", callee); callgraph.AddCallAtLocation(callSiteNode.LocationDescriptor, callerMethod, callee); } } } }