internal static void VerifyOperationTree(this Compilation compilation, string symbolToVerify, string expectedOperationTree, bool skipImplicitlyDeclaredSymbols = false) { SyntaxTree tree = compilation.SyntaxTrees.First(); SyntaxNode root = tree.GetRoot(); SemanticModel model = compilation.GetSemanticModel(tree); var declarations = new List <DeclarationInfo>(); model.ComputeDeclarationsInNode(root, getSymbol: true, builder: declarations, cancellationToken: CancellationToken.None); var actualTextBuilder = new StringBuilder(); foreach (DeclarationInfo declaration in declarations.Where(d => d.DeclaredSymbol != null).OrderBy(d => d.DeclaredSymbol.ToTestDisplayString())) { if (!CanHaveExecutableCodeBlock(declaration.DeclaredSymbol)) { continue; } if (skipImplicitlyDeclaredSymbols && declaration.DeclaredSymbol.IsImplicitlyDeclared) { continue; } if (!string.IsNullOrEmpty(symbolToVerify) && !declaration.DeclaredSymbol.Name.Equals(symbolToVerify, StringComparison.Ordinal)) { continue; } actualTextBuilder.Append(declaration.DeclaredSymbol.ToTestDisplayString()); if (declaration.ExecutableCodeBlocks.Length == 0) { actualTextBuilder.Append($" ('0' executable code blocks)"); } else { // Workaround for https://github.com/dotnet/roslyn/issues/11903 - skip the IOperation for EndBlockStatement. ImmutableArray <SyntaxNode> executableCodeBlocks = declaration.ExecutableCodeBlocks; if (declaration.DeclaredSymbol.Kind == SymbolKind.Method && compilation.Language == LanguageNames.VisualBasic) { executableCodeBlocks = executableCodeBlocks.RemoveAt(executableCodeBlocks.Length - 1); } foreach (SyntaxNode executableCodeBlock in executableCodeBlocks) { actualTextBuilder.Append(Environment.NewLine); AppendOperationTree(model, executableCodeBlock, actualTextBuilder, initialIndent: 2); } } actualTextBuilder.Append(Environment.NewLine); } OperationTreeVerifier.Verify(expectedOperationTree, actualTextBuilder.ToString()); }