/* 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); } } } }
private static CallGraph<MethodDescriptor, LocationDescriptor> ReBuildCallGraph(Dispatcher dispatcher, Solution solution) { var callgraph = new CallGraph<MethodDescriptor, LocationDescriptor>(); // pg.PropagateDeletionOfNodes(); foreach (var e in dispatcher.GetAllEntites()) { var entityProcessor = new MethodEntityProcessor((MethodEntity)e, dispatcher);// e.GetEntityProcessor(dispatcher); var methodEntity = (MethodEntity)entityProcessor.Entity; if (methodEntity.MethodDescriptor.ToString().Contains("Main")) { callgraph.AddRootMethod(methodEntity.MethodDescriptor); } // Updates the callGraph UpdateCallGraph(entityProcessor, callgraph, solution); } //callgraph.Save("cg_d.dot"); return callgraph; }
/// <summary> /// Try to get the roslyn methods on the fly /// Currently works with one project. /// </summary> public void AnalyzeOnDemand() { Contract.Assert(this.Dispatcher != null); var cancellationToken = new CancellationTokenSource(); var projectIDs = this.Solution.GetProjectDependencyGraph().GetTopologicallySortedProjects(cancellationToken.Token); foreach (var projectId in projectIDs) { var project = this.Solution.GetProject(projectId); var compilation = project.GetCompilationAsync().Result; var triple = ProjectCodeProvider.GetProviderContainingEntryPointAsync(project, cancellationToken.Token).Result; var provider = triple.Item1; IMethodSymbol mainSymbol = triple.Item2; var tree = triple.Item3; if (provider != null) { var model = provider.Compilation.GetSemanticModel(tree); cancellationToken.Cancel(); // cancel out outstanding processing tasks var methodVisitor = new MethodSyntaxProcessor(model, tree, mainSymbol); var mainMethodEntity = methodVisitor.ParseMethod(); this.Dispatcher.RegisterEntity(mainMethodEntity.EntityDescriptor, mainMethodEntity); var mainEntityProcessor = new MethodEntityProcessor((MethodEntity)mainMethodEntity, this.Dispatcher); //var mainMethodDescriptor = new MethodDescriptor(mainSymbol); //var mainMethodEntityDescriptor = EntityFactory.Create(mainMethodDescriptor); //var mainEntityProcessor = this.Dispatcher.GetEntityWithProcessorAsync(mainMethodEntityDescriptor).Result ; // Just a test //mainEntityProcessor.MethodEntity.CurrentContext = new CallConext<AMethod, ANode>(mainEntityProcessor.MethodEntity.Method, null, null); mainEntityProcessor.DoAnalysis(); Logger.Instance.Log("SolutionAnalyzer", "AnalyzeOnDemand", "--- Done with propagation ---"); } } if (this.Dispatcher is QueueingDispatcher) { var qd = (QueueingDispatcher)this.Dispatcher; while (!qd.IsDoneProcessing) { Logger.Instance.Log("SolutionAnalyzer", "AnalyzeOnDemand", "Waiting for the queue to empty up..."); Thread.Sleep(1000); } } }