Ejemplo n.º 1
0
 public InferenceDisassembler(VMConstants constants, KoiStream koiStream)
 {
     Constants   = constants ?? throw new ArgumentNullException(nameof(constants));
     KoiStream   = koiStream ?? throw new ArgumentNullException(nameof(koiStream));
     _decoder    = new InstructionDecoder(constants, KoiStream.Contents.CreateReader());
     _processor  = new InstructionProcessor(this);
     _cfgBuilder = new ControlFlowGraphBuilder();
 }
Ejemplo n.º 2
0
        public static ControlFlowGraph CreateControlFlowGraph(MethodDefinition method)
        {
            if (null == method)
            {
                throw new ArgumentNullException("method");
            }
            ControlFlowGraphBuilder builder = new ControlFlowGraphBuilder(method);

            return(builder.BuildGraph());
        }
Ejemplo n.º 3
0
        private BlockStatement DecompileMethodPartially(MethodBody body, out DecompilationContext context, bool needDecompiledMember = false)
        {
            context = null;

            if (this.IsCachingEnabled && this.cacheService.IsDecompiledMemberInCache(body.Method, this.language, this.renameInvalidMembers))
            {
                CachedDecompiledMember cachedDecompiledMember = this.cacheService.GetDecompiledMemberFromCache(body.Method, this.language, this.renameInvalidMembers);
                return(cachedDecompiledMember.Member.Statement as BlockStatement);
            }

            //Performance improvement
            ControlFlowGraph cfg = new ControlFlowGraphBuilder(body.Method).CreateGraph();

            if (cfg.Blocks.Length > 2)
            {
                return(null);
            }

            BlockStatement block;

            try
            {
                DecompilationPipeline pipeline;
                DecompilationContext  decompilationContext =
                    new DecompilationContext(new MethodSpecificContext(body), this.typeContext ?? new TypeSpecificContext(body.Method.DeclaringType));
                if (!needDecompiledMember)
                {
                    decompilationContext.MethodContext.EnableEventAnalysis = false;
                }

                pipeline = new DecompilationPipeline(BaseLanguage.IntermediateRepresenationPipeline.Steps, decompilationContext);

                context = pipeline.Run(body);

                block = pipeline.Body;
            }
            catch (Exception ex)
            {
                this.ExceptionsWhileDecompiling.Add(body.Method);

                block = new BlockStatement();
                block.AddStatement(new ExceptionStatement(ex, body.Method));

                OnExceptionThrown(ex);
            }

            return(block);
        }
Ejemplo n.º 4
0
        private BlockStatement GetStatements(MethodBody body)
        {
            //Performance improvement
            ControlFlowGraph cfg = new ControlFlowGraphBuilder(body.Method).CreateGraph();

            if (cfg.Blocks.Length > 2)
            {
                return(null);
            }

            DecompilationPipeline pipeline = new DecompilationPipeline(BaseLanguage.IntermediateRepresenationPipeline.Steps,
                                                                       new DecompilationContext(new MethodSpecificContext(body)
            {
                EnableEventAnalysis = false
            }, new TypeSpecificContext(body.Method.DeclaringType)));

            pipeline.Run(body);
            return(pipeline.Body);
        }
Ejemplo n.º 5
0
        public static void RunExpressionTest(InstructionSpan instructions, Expression expectedExpression)
        {
            // Add a `pop` to the end to make it a full statement
            instructions = BuildSpan(
                instructions.First.Offset,
                Enumerable.Concat(instructions, new[] { Instruction.Create(OpCodes.Pop) }));

            var controlFlowGraph = ControlFlowGraphBuilder.Build(instructions.ToList(), Array.Empty <ExceptionHandler>());
            var actualGraph      = SyntaxGraphBuilder.Create(controlFlowGraph, new MethodVariables());

            // Extract the expression
            Assert.Equal(1, actualGraph.Nodes.Count);

            var node = actualGraph.Nodes.First();

            Assert.Equal(1, node.Statements.Count);
            var discardStatement = Assert.IsType <DiscardStatement>(node.Statements.Single());

            Assert.Equal(expectedExpression, discardStatement.Value);
        }
Ejemplo n.º 6
0
        private void Transform(FunctionDeclarationSyntax function, LiveVariables liveness)
        {
            var graph   = function.ControlFlow;
            var builder = new ControlFlowGraphBuilder(graph.VariableDeclarations);

            foreach (var block in graph.BasicBlocks)
            {
                var blockBuilder = builder.NewBlock();
                if (block.Number != blockBuilder.BlockNumber)
                {
                    throw new Exception("New block number does not match old block number");
                }

                foreach (var statement in block.ExpressionStatements)
                {
                    // Copy the existing statement
                    blockBuilder.Add(statement);

                    var before = liveness.Before(statement);
                    var after  = liveness.After(statement);
                    // dead = live before and not live after
                    var dead = ((BitArray)after.Clone()).Not().And(before);
                    foreach (var variableNumber in dead.TrueIndexes())
                    {
                        var variable = graph.VariableDeclarations[variableNumber];
                        if (variable.Type is ObjectType type &&
                            type.IsOwned)
                        {
                            // The delete happens after the last statement
                            var span = new TextSpan(statement.Span.End, 0);
                            blockBuilder.AddDelete(new VariableReference(variableNumber, span), type, span);
                        }
                    }
                }
                // TODO what about if there is a variable delete after the terminator?
                blockBuilder.Add(block.Terminator);
            }

            function.ControlFlow = builder.Build();
        }
Ejemplo n.º 7
0
        private static ConstructorDeclaration BuildDefaultConstructor(
            ClassDeclarationSyntax classDeclaration)
        {
            var className       = classDeclaration.FullName;
            var constructorName = className.Qualify(SpecialName.New);
            var selfType        = ((Metatype)classDeclaration.Type.Resolved()).Instance;
            var selfName        = className.Qualify(SpecialName.Self);
            var selfParameter   = new Parameter(true, selfName, selfType);
            var parameters      = selfParameter.Yield().ToFixedList();
            var constructorType = new FunctionType(selfType.Yield(), selfType);

            var graph = new ControlFlowGraphBuilder();

            graph.AddParameter(true, selfType, SpecialName.Self);
            var block = graph.NewBlock();

            block.AddReturn();
            var defaultConstructor = new ConstructorDeclaration(constructorName, constructorType,
                                                                parameters, selfType, graph.Build());

            return(defaultConstructor);
        }
Ejemplo n.º 8
0
 internal static ReachabilityAnalysis Create(Statement statement, Func<AstNode, CancellationToken, ResolveResult> resolver, CSharpTypeResolveContext typeResolveContext, CancellationToken cancellationToken)
 {
     var cfgBuilder = new ControlFlowGraphBuilder();
     var cfg = cfgBuilder.BuildControlFlowGraph(statement, resolver, typeResolveContext, cancellationToken);
     return Create(cfg, cancellationToken);
 }
Ejemplo n.º 9
0
 public static ReachabilityAnalysis Create(Statement statement, CSharpAstResolver resolver = null, CancellationToken cancellationToken = default(CancellationToken))
 {
     var cfgBuilder = new ControlFlowGraphBuilder();
     var cfg = cfgBuilder.BuildControlFlowGraph(statement, resolver, cancellationToken);
     return Create(cfg, cancellationToken);
 }
Ejemplo n.º 10
0
        public static void ValidateIOperations(Func <Compilation> createCompilation)
        {
            if (!EnableVerifyIOperation)
            {
                return;
            }

            var compilation = createCompilation();
            var roots       = ArrayBuilder <IOperation> .GetInstance();

            var stopWatch = new Stopwatch();

            if (!System.Diagnostics.Debugger.IsAttached)
            {
                stopWatch.Start();
            }

            void checkTimeout()
            {
                const int timeout = 15000;

                Assert.False(stopWatch.ElapsedMilliseconds > timeout, $"ValidateIOperations took too long: {stopWatch.ElapsedMilliseconds} ms");
            }

            foreach (var tree in compilation.SyntaxTrees)
            {
                var semanticModel = compilation.GetSemanticModel(tree);
                var root          = tree.GetRoot();

                foreach (var node in root.DescendantNodesAndSelf())
                {
                    checkTimeout();

                    var operation = semanticModel.GetOperation(node);
                    if (operation != null)
                    {
                        // Make sure IOperation returned by GetOperation(syntaxnode) will have same syntaxnode as the given syntaxnode(IOperation.Syntax == syntaxnode).
                        Assert.True(node == operation.Syntax, $"Expected : {node} - Actual : {operation.Syntax}");

                        Assert.True(operation.Type == null || !operation.MustHaveNullType(), $"Unexpected non-null type: {operation.Type}");

                        Assert.Same(semanticModel, operation.SemanticModel);
                        Assert.NotSame(semanticModel, ((Operation)operation).OwningSemanticModel);
                        Assert.NotNull(((Operation)operation).OwningSemanticModel);
                        Assert.Same(semanticModel, ((Operation)operation).OwningSemanticModel.ContainingModelOrSelf);
                        Assert.Same(semanticModel, semanticModel.ContainingModelOrSelf);

                        if (operation.Parent == null)
                        {
                            roots.Add(operation);
                        }
                    }
                }
            }

            var explicitNodeMap = new Dictionary <SyntaxNode, IOperation>();
            var visitor         = TestOperationVisitor.Singleton;

            foreach (var root in roots)
            {
                foreach (var operation in root.DescendantsAndSelf())
                {
                    checkTimeout();

                    if (!operation.IsImplicit)
                    {
                        try
                        {
                            explicitNodeMap.Add(operation.Syntax, operation);
                        }
                        catch (ArgumentException)
                        {
                            Assert.False(true, $"Duplicate explicit node for syntax ({operation.Syntax.RawKind}): {operation.Syntax.ToString()}");
                        }
                    }

                    visitor.Visit(operation);
                }

                stopWatch.Stop();
                checkControlFlowGraph(root);
                stopWatch.Start();
            }

            roots.Free();
            stopWatch.Stop();
            return;

            void checkControlFlowGraph(IOperation root)
            {
                switch (root)
                {
                case IBlockOperation blockOperation:
                    // https://github.com/dotnet/roslyn/issues/27593 tracks adding ControlFlowGraph support in script code.
                    if (blockOperation.Syntax.SyntaxTree.Options.Kind != SourceCodeKind.Script)
                    {
                        ControlFlowGraphVerifier.GetFlowGraph(compilation, ControlFlowGraphBuilder.Create(blockOperation));
                    }

                    break;

                case IMethodBodyOperation methodBody:
                case IConstructorBodyOperation constructorBody:
                case IFieldInitializerOperation fieldInitializerOperation:
                case IPropertyInitializerOperation propertyInitializerOperation:
                    ControlFlowGraphVerifier.GetFlowGraph(compilation, ControlFlowGraphBuilder.Create(root));
                    break;

                case IParameterInitializerOperation parameterInitializerOperation:
                    // https://github.com/dotnet/roslyn/issues/27594 tracks adding support for getting ControlFlowGraph for parameter initializers for local functions.
                    if ((parameterInitializerOperation.Parameter.ContainingSymbol as IMethodSymbol)?.MethodKind != MethodKind.LocalFunction)
                    {
                        ControlFlowGraphVerifier.GetFlowGraph(compilation, ControlFlowGraphBuilder.Create(root));
                    }
                    break;
                }
            }
        }
Ejemplo n.º 11
0
        private static async Task <int> Execute(string assemblyPath, string typeName, string memberName, string outFile, string format)
        {
            var disassembler = new DisassemblerSession();

            var disassembly = await disassembler.LoadAsync(assemblyPath);

            var type = disassembly.FindType(typeName);

            if (type == null)
            {
                return(Error($"could not find type: {typeName}"));
            }
            var member = type.Members.FirstOrDefault(t => t.Name.Equals(memberName));

            if (member == null)
            {
                return(Error($"could not find member: {memberName} in type {typeName}"));
            }

            ControlFlowGraph graph = null;

            if (member.MemberType == MemberType.Method)
            {
                graph = ControlFlowGraphBuilder.Build(((MethodDefinition)member.Definition).Body);
            }
            else
            {
                return(Error($"Member type not supported: {member.MemberType}"));
            }

            if (!string.IsNullOrEmpty(outFile))
            {
                format = string.IsNullOrEmpty(format) ? "dot" : format;
                if (!Formats.TryGetValue(format, out var handler))
                {
                    return(Error($"Unknown format: {format}"));
                }
                await handler(graph, outFile);
            }
            else
            {
                Console.WriteLine($"Control flow graph for {typeName}.{memberName}");

                foreach (var node in graph.Nodes)
                {
                    Console.WriteLine();
                    Console.WriteLine(node.ToString());
                }

                // Write Exception handlers
                foreach (var handler in graph.ExceptionHandlers)
                {
                    Console.WriteLine();
                    Console.WriteLine("  .try {");
                    Console.WriteLine($"    IL_{handler.TryStart.Offset:X4} -> IL_{handler.TryEnd.Offset:X4}");
                    Console.WriteLine("  }");
                    Console.WriteLine($"  {FormatHandlerType(handler)} {{");
                    if (handler.HandlerType == ExceptionHandlerType.Filter)
                    {
                        Console.WriteLine($"    IL_{handler.FilterStart.Offset:X4} -> IL_{handler.HandlerStart.Offset:X4}");
                        Console.WriteLine("  }");
                        Console.WriteLine("  .catch {");
                    }
                    Console.WriteLine($"    IL_{handler.HandlerStart.Offset:X4} -> IL_{handler.HandlerEnd.Offset:X4}");
                    Console.WriteLine("  }");
                }
            }

            Console.WriteLine();

            return(0);
        }
Ejemplo n.º 12
0
            void AddIssueFor(AstNode currentFunction)
            {
                if (IsAsync(currentFunction))
                {
                    return;
                }

                //Only suggest modifying functions that return void, Task or Task<T>.
                IType returnType = GetReturnType(ctx, currentFunction);

                if (returnType == null)
                {
                    return;
                }

                bool  isVoid     = false;
                IType resultType = null;

                switch (returnType.FullName)
                {
                case "System.Void":
                    isVoid = true;
                    break;

                case "System.Threading.Tasks.Task":
                    resultType = returnType.IsParameterized ? returnType.TypeArguments.FirstOrDefault() : null;
                    break;

                default:
                    return;
                }

                var functionBody     = currentFunction.GetChildByRole(Roles.Body);
                var statements       = GetStatements(functionBody).ToList();
                var returnStatements = statements.OfType <ReturnStatement>().ToList();

                var invocations = new List <InvocationExpression>();
                var nextInChain = new Dictionary <InvocationExpression, InvocationExpression>();

                foreach (var invocation in currentFunction.Descendants.OfType <InvocationExpression>())
                {
                    if (invocation.Arguments.Count != 1)
                    {
                        continue;
                    }

                    var       lambdaOrDelegate = invocation.Arguments.Single();
                    Statement lambdaBody;
                    if (lambdaOrDelegate is LambdaExpression)
                    {
                        lambdaBody = lambdaOrDelegate.GetChildByRole(LambdaExpression.BodyRole) as BlockStatement;
                        if (lambdaBody == null)
                        {
                            continue;
                        }
                    }
                    else if (lambdaOrDelegate is AnonymousMethodExpression)
                    {
                        lambdaBody = lambdaOrDelegate.GetChildByRole(Roles.Body);
                    }
                    else
                    {
                        continue;
                    }

                    var resolveResult = ctx.Resolve(invocation) as MemberResolveResult;
                    if (resolveResult == null)
                    {
                        continue;
                    }
                    if (resolveResult.Member.FullName != "System.Threading.Tasks.Task.ContinueWith")
                    {
                        continue;
                    }

                    var parentExpression = invocation.Parent as Expression;
                    if (parentExpression != null)
                    {
                        var mreParent = parentExpression as MemberReferenceExpression;
                        if (mreParent == null || mreParent.MemberName != "ContinueWith")
                        {
                            continue;
                        }

                        var parentInvocation = mreParent.Parent as InvocationExpression;
                        if (parentInvocation == null || parentInvocation.Arguments.Count != 1)
                        {
                            continue;
                        }

                        nextInChain[invocation] = parentInvocation;
                    }

                    invocations.Add(invocation);
                }

                if (isVoid && invocations.Count == 0)
                {
                    //Prevent functions like void Foo() {} from being accepted
                    return;
                }

                string taskCompletionSourceIdentifier     = null;
                InvocationExpression returnedContinuation = null;

                if (isVoid)
                {
                    if (returnStatements.Any())
                    {
                        return;
                    }
                }
                else if (!isVoid)
                {
                    if (returnStatements.Count() != 1)
                    {
                        return;
                    }

                    var returnStatement = returnStatements.Single();
                    if (functionBody.Statements.Last() != returnStatement)
                    {
                        return;
                    }

                    var match = ReturnTaskCompletionSourcePattern.Match(returnStatement);
                    if (match.Success)
                    {
                        var taskCompletionSource = match.Get <IdentifierExpression>("target").Single();
                        var taskCompletionSourceResolveResult = ctx.Resolve(taskCompletionSource);

                        //Make sure the TaskCompletionSource is a local variable
                        if (!(taskCompletionSourceResolveResult is LocalResolveResult) ||
                            taskCompletionSourceResolveResult.Type.FullName != "System.Threading.Tasks.TaskCompletionSource")
                        {
                            return;
                        }
                        taskCompletionSourceIdentifier = taskCompletionSource.Identifier;

                        var cfgBuilder = new ControlFlowGraphBuilder();
                        var cachedControlFlowGraphs = new Dictionary <BlockStatement, IList <ControlFlowNode> >();

                        //Make sure there are no unsupported uses of the task completion source
                        foreach (var identifier in functionBody.Descendants.OfType <Identifier>())
                        {
                            if (identifier.Name != taskCompletionSourceIdentifier)
                            {
                                continue;
                            }

                            var statement         = identifier.GetParent <Statement>();
                            var variableStatement = statement as VariableDeclarationStatement;
                            if (variableStatement != null)
                            {
                                if (functionBody.Statements.First() != variableStatement || variableStatement.Variables.Count != 1)
                                {
                                    //This may actually be valid, but it would add even more complexity to this action
                                    return;
                                }
                                var initializer = variableStatement.Variables.First().Initializer as ObjectCreateExpression;
                                if (initializer == null || initializer.Arguments.Count != 0 || !initializer.Initializer.IsNull)
                                {
                                    return;
                                }

                                var constructedType = ctx.ResolveType(initializer.Type);
                                if (constructedType.FullName != "System.Threading.Tasks.TaskCompletionSource")
                                {
                                    return;
                                }

                                continue;
                            }

                            if (statement == returnStatement)
                            {
                                continue;
                            }

                            if (identifier.Parent is MemberReferenceExpression)
                            {
                                //Right side of the member.
                                //We don't care about this case since it's not a reference to the variable.
                                continue;
                            }

                            //The method's taskCompletionSource can only be used on the left side of a member
                            //reference expression (specifically tcs.SetResult).
                            var identifierExpressionParent = identifier.Parent as IdentifierExpression;
                            if (identifierExpressionParent == null)
                            {
                                return;
                            }
                            var memberReferenceExpression = identifierExpressionParent.Parent as MemberReferenceExpression;
                            if (memberReferenceExpression == null)
                            {
                                return;
                            }

                            if (memberReferenceExpression.MemberName != "SetResult")
                            {
                                //Aside from the final return statement, the only member of task completion source
                                //that can be used is SetResult.
                                //Perhaps future versions could also include SetException and SetCancelled.
                                return;
                            }

                            //We found a SetResult -- we will now find out if it is in a proper context
                            AstNode node = memberReferenceExpression;
                            for (;;)
                            {
                                node = node.Parent;

                                if (node == null)
                                {
                                    //Abort since this is unexpected (it should never happen)
                                    return;
                                }

                                if (node is MethodDeclaration)
                                {
                                    //Ok -- tcs.SetResult is in method declaration
                                    break;
                                }

                                if (node is LambdaExpression || node is AnonymousMethodExpression)
                                {
                                    //It's time to verify if the lambda is supported
                                    var lambdaParent = node.Parent as InvocationExpression;
                                    if (lambdaParent == null || !invocations.Contains(lambdaParent))
                                    {
                                        return;
                                    }
                                    break;
                                }
                            }

                            var containingContinueWith = node.Parent as InvocationExpression;
                            if (containingContinueWith != null)
                            {
                                if (nextInChain.ContainsKey(containingContinueWith))
                                {
                                    //Unsupported: ContinueWith has a SetResult
                                    //but it's not the last in the chain
                                    return;
                                }
                            }

                            var containingFunctionBlock = node is LambdaExpression ? (BlockStatement)node.GetChildByRole(LambdaExpression.BodyRole) : node.GetChildByRole(Roles.Body);

                            //Finally, tcs.SetResult must be at the end of its method
                            IList <ControlFlowNode> nodes;
                            if (!cachedControlFlowGraphs.TryGetValue(containingFunctionBlock, out nodes))
                            {
                                nodes = cfgBuilder.BuildControlFlowGraph(containingFunctionBlock, ctx.CancellationToken);
                                cachedControlFlowGraphs[containingFunctionBlock] = nodes;
                            }

                            var setResultNode = nodes.FirstOrDefault(candidateNode => candidateNode.PreviousStatement == statement);
                            if (setResultNode != null && HasReachableNonReturnNodes(setResultNode))
                            {
                                //The only allowed outgoing nodes are return statements
                                return;
                            }
                        }
                    }
                    else
                    {
                        //Not TaskCompletionSource-based
                        //Perhaps it is return Task.ContinueWith(foo);

                        if (!invocations.Any())
                        {
                            return;
                        }

                        var outerMostInvocations = new List <InvocationExpression>();
                        InvocationExpression currentInvocation = invocations.First();
                        do
                        {
                            outerMostInvocations.Add(currentInvocation);
                        } while (nextInChain.TryGetValue(currentInvocation, out currentInvocation));

                        var lastInvocation = outerMostInvocations.Last();
                        if (returnStatement.Expression != lastInvocation)
                        {
                            return;
                        }

                        //Found return <1>.ContinueWith(<2>);
                        returnedContinuation = lastInvocation;
                    }
                }

                //We do not support "return expr" in continuations
                //The only exception is when the outer method returns that continuation.
                invocations.RemoveAll(invocation => invocation != returnedContinuation &&
                                      invocation.Arguments.First().Children.OfType <Statement>().First().DescendantNodesAndSelf(node => node is Statement).OfType <ReturnStatement>().Any(returnStatement => !returnStatement.Expression.IsNull));

                AddIssue(new CodeIssue(GetFunctionToken(currentFunction),
                                       ctx.TranslateString("Function can be converted to C# 5-style async function"),
                                       ctx.TranslateString("Convert to C# 5-style async function"),
                                       script => {
                    AddOriginalNodeAnnotations(currentFunction);
                    var newFunction = currentFunction.Clone();
                    RemoveOriginalNodeAnnotations(currentFunction);

                    //Set async
                    var lambda = newFunction as LambdaExpression;
                    if (lambda != null)
                    {
                        lambda.IsAsync = true;
                    }
                    var anonymousMethod = newFunction as AnonymousMethodExpression;
                    if (anonymousMethod != null)
                    {
                        anonymousMethod.IsAsync = true;
                    }
                    var methodDeclaration = newFunction as MethodDeclaration;
                    if (methodDeclaration != null)
                    {
                        methodDeclaration.Modifiers |= Modifiers.Async;
                    }

                    TransformBody(invocations, isVoid, resultType != null, returnedContinuation, taskCompletionSourceIdentifier, newFunction.GetChildByRole(Roles.Body));

                    script.Replace(currentFunction, newFunction);
                }));
            }
Ejemplo n.º 13
0
        private static async Task <int> Execute(string assemblyPath, string typeName, string memberName)
        {
            var disassembler = new DisassemblerSession();

            var disassembly = await disassembler.LoadAsync(assemblyPath);

            var type = disassembly.FindType(typeName);

            if (type == null)
            {
                return(Error($"could not find type: {typeName}"));
            }
            var member = type.Members.FirstOrDefault(t => t.Name.Equals(memberName));

            if (member == null)
            {
                return(Error($"could not find member: {memberName} in type {typeName}"));
            }

            ControlFlowGraph graph  = null;
            MethodDefinition method = null;

            if (member.MemberType == MemberType.Method)
            {
                method = (MethodDefinition)member.Definition;
                graph  = ControlFlowGraphBuilder.Build(method.Body);
            }
            else
            {
                return(Error($"Member type not supported: {member.MemberType}"));
            }

            var syntax = SyntaxGraphBuilder.Create(graph, method);

            var arguments = string.Join(", ", method.Parameters.Select(p => $"{p.ParameterType.FullName} {p.Name}"));

            Console.WriteLine($"Syntax analysis for {typeName}.{memberName}({arguments})");

            if (method.Body.Variables.Any())
            {
                Console.WriteLine();

                foreach (var local in method.Body.Variables)
                {
                    Console.WriteLine($"  .local {local.VariableType.FullName} _{local.Index}");
                }
            }

            foreach (var node in syntax.Nodes)
            {
                Console.WriteLine();
                Console.WriteLine($"  {node.DisplayName} : {{");
                foreach (var statement in node.Statements)
                {
                    Console.WriteLine($"    {statement}");
                }
                Console.WriteLine($"  }}{FormatLinks(node)}");
            }

            Console.WriteLine();

            return(0);
        }
Ejemplo n.º 14
0
        public static void RunControlFlowTest(InstructionSpan instructions, ControlFlowGraph expectedGraph)
        {
            var actualGraph = ControlFlowGraphBuilder.Build(instructions.ToList(), Array.Empty <ExceptionHandler>());

            Assert.Equal(expectedGraph, actualGraph, TestControlFlowGraphComparer.Instance);
        }