コード例 #1
0
        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);
        }
コード例 #2
0
/*
		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);
					}
				}
			}
        }