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 declarationsBuilder = ArrayBuilder <DeclarationInfo> .GetInstance(); model.ComputeDeclarationsInNode(root, associatedSymbol: null, getSymbol: true, builder: declarationsBuilder, cancellationToken: CancellationToken.None); var actualTextBuilder = new StringBuilder(); foreach (DeclarationInfo declaration in declarationsBuilder.ToArrayAndFree().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); model.AppendOperationTree(executableCodeBlock, actualTextBuilder, initialIndent: 2); } } actualTextBuilder.Append(Environment.NewLine); } OperationTreeVerifier.Verify(expectedOperationTree, actualTextBuilder.ToString()); }