Beispiel #1
0
        // TODO: Implement proper exception handling
        private async Task <GeneratedGraphs> GenerateGraphsImpl(MethodLocation location, FlowGraphId graphId)
        {
            var declarationLocation = location.Method.Locations.FirstOrDefault();

            Contract.Assert(declarationLocation != null);
            Contract.Assert(declarationLocation.IsInSource);

            var root         = declarationLocation.SourceTree.GetRoot();
            var methodSyntax = root.FindNode(declarationLocation.SourceSpan) as BaseMethodDeclarationSyntax;

            Contract.Assert(methodSyntax != null);

            // TODO: Handle the continuation in a logic way
            var document      = this.Solution.GetDocument(root.SyntaxTree);
            var semanticModel = document.GetSemanticModelAsync().Result;

            var builder = new CSharpGraphBuilder(
                this.ModelManager,
                document.Id,
                semanticModel,
                methodSyntax);

            var buildGraph = await builder.BuildAsync();

            var flowGraphTranslator = new FlowGraphTranslator(buildGraph, builder.DisplayGraph, graphId);
            var result = flowGraphTranslator.Translate();

            result.Location = location;

            return(result);
        }
Beispiel #2
0
        private async Task <GeneratedGraphs> LazyGenerateGraphsAsync(MethodLocation location)
        {
            FlowGraphId     graphId;
            GeneratedGraphs result;

            if (this.symbolsToGraphIdMap.TryGetValue((location).Method, out graphId))
            {
                result = this.generatedGraphs[graphId];
            }
            else
            {
                graphId = this.graphIdProvider.GenerateNewId();
                result  = await Task.Run(() => this.GenerateGraphsImpl(location, graphId));

                this.generatedGraphs[graphId] = result;
                this.symbolsToGraphIdMap.Add(location.Method, graphId);
            }

            return(result);
        }
Beispiel #3
0
        public async Task <IReadOnlyList <OuterFlowEdge> > GetCallEdgesToAsync(EnterFlowNode enterNode)
        {
            var results = new List <OuterFlowEdge>();

            var calledMethodLocation = this.GetLocation(enterNode.Graph.Id);
            var references           = await SymbolFinder.FindCallersAsync(calledMethodLocation.Method, this.Solution);

            foreach (var reference in references)
            {
                Contract.Assert(reference.CalledSymbol.Equals(calledMethodLocation.Method));
                var callingMethod = reference.CallingSymbol as IMethodSymbol;
                if (callingMethod == null)
                {
                    continue;
                }

                var callingMethodLocation = new MethodLocation(callingMethod);
                if (!callingMethodLocation.CanBeExplored)
                {
                    continue;
                }

                var graphs = await this.LazyGenerateGraphsAsync(callingMethodLocation);

                foreach (var callNode in graphs.FlowGraph.Nodes.OfType <CallFlowNode>())
                {
                    if (((MethodLocation)callNode.Location).Equals(calledMethodLocation))
                    {
                        // TODO: Store outer edges instead of recreating them every time
                        var callEdge = OuterFlowEdge.CreateMethodCall(new OuterFlowEdgeId(-1), callNode, enterNode);
                        results.Add(callEdge);
                    }
                }
            }

            return(results.ToArray());
        }
Beispiel #4
0
        private FlowNode TryTranslateBorderNode(BuildNode buildNode)
        {
            var borderOp = buildNode.Operation as BorderOperation;

            if (borderOp == null || borderOp.Kind == SpecialOperationKind.Assertion)
            {
                return(null);
            }

            if (borderOp.Kind == SpecialOperationKind.MethodCall || borderOp.Kind == SpecialOperationKind.ExceptionThrow)
            {
                MethodLocation           location;
                IEnumerable <Expression> flowArguments;

                if (borderOp.Arguments.Any(arg => arg == null))
                {
                    // We cannot model method calls without properly modelling all their arguments first
                    location      = new MethodLocation(borderOp.Method, isExplorationDisabled: true);
                    flowArguments = Enumerable.Empty <Expression>();
                }
                else
                {
                    // TODO: Enable a configurable and extensible approach instead of this hack
                    // Disable exploring the methods from the tool evaluation
                    bool isExplorationDisabled =
                        borderOp.Method.ContainingType.ToString() == "EvaluationTests.Annotations.Evaluation";

                    location = new MethodLocation(borderOp.Method, isExplorationDisabled);
                    var buildArguments = borderOp.Arguments.SelectMany(typeModel => typeModel.AssignmentRight);
                    flowArguments = buildArguments.Select(expression => this.TranslateExpression(expression));
                }

                if (borderOp.Kind == SpecialOperationKind.MethodCall)
                {
                    var returnAssignments = buildNode.VariableModel?.AssignmentLeft
                                            .Select(buildVar => this.TranslateVariable(buildVar));

                    // We don't allow calling base constructors, so the only way to call it is with the "new" operator
                    // TODO: Propagate the information about constructor call other way when the above is supported
                    var callKind = (borderOp.Method.MethodKind == MethodKind.Constructor)
                        ? CallKind.ObjectCreation
                        : borderOp.Method.IsStatic
                            ? CallKind.Static
                            : CallKind.Instance;

                    bool isObjectCreation = (borderOp.Method.MethodKind == MethodKind.Constructor);

                    return(this.builder.AddCallNode(location, flowArguments, returnAssignments, callKind, buildNode.Flags));
                }
                else
                {
                    Contract.Assert(borderOp.Kind == SpecialOperationKind.ExceptionThrow);

                    return(this.builder.AddThrowExceptionNode(location, flowArguments, buildNode.Flags));
                }
            }
            else
            {
                Contract.Assert(borderOp.Kind == SpecialOperationKind.Return);

                var returnValues = buildNode.ValueModel?.AssignmentRight
                                   .Select(expression => this.TranslateExpression(expression))
                                   .ToImmutableArray();

                if ((returnValues == null || returnValues.Value.Length == 0) &&
                    this.BuildGraph.MethodSyntax.Kind() == SyntaxKind.ConstructorDeclaration)
                {
                    // A constructor returns "this" variable by convention
                    var buildThis = this.BuildGraph.Variables.First(v => v.Origin == VariableOrigin.This);
                    returnValues = ImmutableArray.Create((Expression)this.TranslateVariable(buildThis));
                }

                return(this.builder.AddReturnNode(returnValues, buildNode.Flags));
            }
        }
Beispiel #5
0
 // TODO: Consider implementing also == operator
 public bool Equals(MethodLocation other)
 {
     return(this.Method.Equals(other.Method));
 }