Ejemplo n.º 1
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;
                }
            }
        }