From 9d772785f1a6060e26cf112db25f7dd20021aee0 Mon Sep 17 00:00:00 2001 From: Manish Vasani Date: Tue, 14 Mar 2017 13:43:05 -0700 Subject: [PATCH 1/3] Add helper methods to Verify operation tree for annonated text within a source file. These APIs will be used in autogenerated unit test for Operation tree verification. --- .../Semantic/IOperation/IOperationTests.cs | 2 +- .../IOperationTests_ISymbolInitializer.cs | 2 +- .../Utilities/CSharp/SemanticModelTestBase.cs | 39 ++++++++++++++++++- .../VisualBasic/SemanticModelTestBase.vb | 29 ++++++++++++++ .../Semantic/IOperation/IOperationTests.vb | 2 +- .../IOperationTests_ISymbolInitializer.vb | 2 +- .../Compilation/CompilationExtensions.cs | 13 +------ .../Compilation/OperationTreeVerifier.cs | 11 ++++++ .../Extensions/SemanticModelExtensions.cs | 12 ++++++ .../Utilities/Portable/TestUtilities.csproj | 1 + 10 files changed, 96 insertions(+), 17 deletions(-) create mode 100644 src/Test/Utilities/Portable/Extensions/SemanticModelExtensions.cs diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests.cs index 481617dd9330a..2aa11ad5a61de 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests { - public partial class IOperationTests : CompilingTestBase + public partial class IOperationTests : SemanticModelTestBase { [Fact] [WorkItem(382240, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=382240")] diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.cs index c24cc6deae1ef..786a849684702 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests { - public partial class IOperationTests : CompilingTestBase + public partial class IOperationTests : SemanticModelTestBase { [Fact, WorkItem(17595, "https://github.com/dotnet/roslyn/issues/17595")] public void NoInitializers() diff --git a/src/Compilers/Test/Utilities/CSharp/SemanticModelTestBase.cs b/src/Compilers/Test/Utilities/CSharp/SemanticModelTestBase.cs index 7994fd0ecdf71..d9c8e73587e5f 100644 --- a/src/Compilers/Test/Utilities/CSharp/SemanticModelTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/SemanticModelTestBase.cs @@ -6,9 +6,8 @@ using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; -using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; -using Roslyn.Test.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -220,5 +219,41 @@ protected CompilationUtils.SemanticInfoSummary GetSemanticInfoForTest(string tes { return GetSemanticInfoForTest(testSrc); } + + protected string GetOperationTreeForTest(CSharpCompilation compilation) + where TSyntaxNode: SyntaxNode + { + var tree = compilation.SyntaxTrees[0]; + var model = compilation.GetSemanticModel(tree); + SyntaxNode syntaxNode = GetSyntaxNodeOfTypeForBinding(GetSyntaxNodeList(tree)); + if (syntaxNode == null) + { + return null; + } + + var operation = model.GetOperationInternal(syntaxNode); + return operation != null ? OperationTreeVerifier.GetOperationTree(operation) : null; + } + + protected string GetOperationTreeForTest(string testSrc, string expectedOperationTree, CSharpParseOptions parseOptions = null) + where TSyntaxNode : SyntaxNode + { + var compilation = CreateCompilationWithMscorlib(testSrc, new[] { SystemCoreRef }, parseOptions: parseOptions); + return GetOperationTreeForTest(compilation); + } + + protected void VerifyOperationTreeForTest(CSharpCompilation compilation, string expectedOperationTree) + where TSyntaxNode : SyntaxNode + { + var actualOperationTree = GetOperationTreeForTest(compilation); + OperationTreeVerifier.Verify(expectedOperationTree, actualOperationTree); + } + + protected void VerifyOperationTreeForTest(string testSrc, string expectedOperationTree, CSharpParseOptions parseOptions = null) + where TSyntaxNode : SyntaxNode + { + var actualOperationTree = GetOperationTreeForTest(testSrc, expectedOperationTree, parseOptions); + OperationTreeVerifier.Verify(expectedOperationTree, actualOperationTree); + } } } diff --git a/src/Compilers/Test/Utilities/VisualBasic/SemanticModelTestBase.vb b/src/Compilers/Test/Utilities/VisualBasic/SemanticModelTestBase.vb index 7df729311b49b..f3ec8a71cb2b7 100644 --- a/src/Compilers/Test/Utilities/VisualBasic/SemanticModelTestBase.vb +++ b/src/Compilers/Test/Utilities/VisualBasic/SemanticModelTestBase.vb @@ -1,5 +1,6 @@ ' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -151,4 +152,32 @@ Public MustInherit Class SemanticModelTestBase : Inherits BasicTestBase ).Where(Function(s) anyArity OrElse DirectCast(s, Symbol).GetArity() = arity.Value).ToList() End Function + Friend Function GetOperationTreeForTest(Of TSyntaxNode As SyntaxNode)(compilation As VisualBasicCompilation, fileName As String, Optional which As Integer = 0) As String + Dim node As SyntaxNode = CompilationUtils.FindBindingText(Of TSyntaxNode)(compilation, fileName, which) + If node Is Nothing Then + Return Nothing + End If + + Dim tree = (From t In compilation.SyntaxTrees Where t.FilePath = fileName).Single() + Dim semanticModel = compilation.GetSemanticModel(tree) + Dim operation = semanticModel.GetOperationInternal(node) + Return If(operation IsNot Nothing, OperationTreeVerifier.GetOperationTree(operation), Nothing) + End Function + + Friend Function GetOperationTreeForTest(Of TSyntaxNode As SyntaxNode)(testSrc As String, Optional parseOptions As VisualBasicParseOptions = Nothing, Optional which As Integer = 0) As String + Dim fileName = "a.vb" + Dim syntaxTree = Parse(testSrc, fileName, parseOptions) + Dim compilation = CreateCompilationWithMscorlib(syntaxTree) + Return GetOperationTreeForTest(Of TSyntaxNode)(compilation, fileName, which) + End Function + + Friend Sub VerifyOperationTreeForTest(Of TSyntaxNode As SyntaxNode)(compilation As VisualBasicCompilation, fileName As String, expectedOperationTree As String, Optional which As Integer = 0) + Dim actualOperationTree = GetOperationTreeForTest(Of TSyntaxNode)(compilation, fileName, which) + OperationTreeVerifier.Verify(expectedOperationTree, actualOperationTree) + End Sub + + Friend Sub VerifyOperationTreeForTest(Of TSyntaxNode As SyntaxNode)(testSrc As String, expectedOperationTree As String, Optional parseOptions As VisualBasicParseOptions = Nothing, Optional which As Integer = 0) + Dim actualOperationTree = GetOperationTreeForTest(Of TSyntaxNode)(testSrc, parseOptions, which) + OperationTreeVerifier.Verify(expectedOperationTree, actualOperationTree) + End Sub End Class diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests.vb index 13ba1cd65eff8..4a136b584d8ad 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests.vb @@ -8,7 +8,7 @@ Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics Partial Public Class IOperationTests - Inherits BasicTestBase + Inherits SemanticModelTestBase Public Sub InvalidUserDefinedOperators() diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.vb index e4f2330030e18..808597b00435b 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.vb @@ -8,7 +8,7 @@ Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics Partial Public Class IOperationTests - Inherits BasicTestBase + Inherits SemanticModelTestBase Public Sub NoInitializers() diff --git a/src/Test/Utilities/Portable/Compilation/CompilationExtensions.cs b/src/Test/Utilities/Portable/Compilation/CompilationExtensions.cs index 7ad9f69b0e77c..935062d382779 100644 --- a/src/Test/Utilities/Portable/Compilation/CompilationExtensions.cs +++ b/src/Test/Utilities/Portable/Compilation/CompilationExtensions.cs @@ -159,7 +159,7 @@ internal static void VerifyOperationTree(this Compilation compilation, SyntaxNod var actualTextBuilder = new StringBuilder(); SemanticModel model = compilation.GetSemanticModel(node.SyntaxTree); AppendOperationTree(model, node, actualTextBuilder); - VerifyOperationTree(expectedOperationTree, actualTextBuilder.ToString()); + OperationTreeVerifier.Verify(expectedOperationTree, actualTextBuilder.ToString()); } internal static void VerifyOperationTree(this Compilation compilation, string expectedOperationTree, bool skipImplicitlyDeclaredSymbols = false) @@ -218,7 +218,7 @@ internal static void VerifyOperationTree(this Compilation compilation, string sy actualTextBuilder.Append(Environment.NewLine); } - VerifyOperationTree(expectedOperationTree, actualTextBuilder.ToString()); + OperationTreeVerifier.Verify(expectedOperationTree, actualTextBuilder.ToString()); } private static void AppendOperationTree(SemanticModel model, SyntaxNode node, StringBuilder actualTextBuilder, int initialIndent = 0) @@ -235,15 +235,6 @@ private static void AppendOperationTree(SemanticModel model, SyntaxNode node, St } } - private static void VerifyOperationTree(string expectedOperationTree, string actualOperationTree) - { - char[] newLineChars = Environment.NewLine.ToCharArray(); - string actual = actualOperationTree.Trim(newLineChars); - expectedOperationTree = expectedOperationTree.Trim(newLineChars); - expectedOperationTree = Regex.Replace(expectedOperationTree, "([^\r])\n", "$1" + Environment.NewLine); - AssertEx.AreEqual(expectedOperationTree, actual); - } - internal static bool CanHaveExecutableCodeBlock(ISymbol symbol) { switch (symbol.Kind) diff --git a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs index 6c47686b35e67..5e36971a2248b 100644 --- a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs +++ b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs @@ -5,8 +5,10 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Text; +using System.Text.RegularExpressions; using Microsoft.CodeAnalysis.Semantics; using Microsoft.CodeAnalysis.Test.Extensions; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Test.Utilities @@ -42,6 +44,15 @@ public static string GetOperationTree(IOperation operation, int initialIndent = return walker._builder.ToString(); } + public static void Verify(string expectedOperationTree, string actualOperationTree) + { + char[] newLineChars = Environment.NewLine.ToCharArray(); + string actual = actualOperationTree.Trim(newLineChars); + expectedOperationTree = expectedOperationTree.Trim(newLineChars); + expectedOperationTree = Regex.Replace(expectedOperationTree, "([^\r])\n", "$1" + Environment.NewLine); + AssertEx.AreEqual(expectedOperationTree, actual); + } + #region Logging helpers private void LogCommonPropertiesAndNewLine(IOperation operation) diff --git a/src/Test/Utilities/Portable/Extensions/SemanticModelExtensions.cs b/src/Test/Utilities/Portable/Extensions/SemanticModelExtensions.cs new file mode 100644 index 0000000000000..1ed933cc5a014 --- /dev/null +++ b/src/Test/Utilities/Portable/Extensions/SemanticModelExtensions.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.CodeAnalysis.Test.Extensions +{ + public static class SemanticModelExtensions + { + public static IOperation GetOperationInternal(this SemanticModel model, SyntaxNode node) + { + return model.GetOperationInternal(node); + } + } +} diff --git a/src/Test/Utilities/Portable/TestUtilities.csproj b/src/Test/Utilities/Portable/TestUtilities.csproj index df3a0fce2a553..37716cf9d1cef 100644 --- a/src/Test/Utilities/Portable/TestUtilities.csproj +++ b/src/Test/Utilities/Portable/TestUtilities.csproj @@ -129,6 +129,7 @@ + From cb01f0b0bdf86afe42145eeea857be43caa2a959 Mon Sep 17 00:00:00 2001 From: Manish Vasani Date: Tue, 14 Mar 2017 16:17:13 -0700 Subject: [PATCH 2/3] Address PR feedback and add comment --- .../Utilities/Portable/Extensions/SemanticModelExtensions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Test/Utilities/Portable/Extensions/SemanticModelExtensions.cs b/src/Test/Utilities/Portable/Extensions/SemanticModelExtensions.cs index 1ed933cc5a014..a69daa2103b26 100644 --- a/src/Test/Utilities/Portable/Extensions/SemanticModelExtensions.cs +++ b/src/Test/Utilities/Portable/Extensions/SemanticModelExtensions.cs @@ -6,6 +6,7 @@ public static class SemanticModelExtensions { public static IOperation GetOperationInternal(this SemanticModel model, SyntaxNode node) { + // Invoke the GetOperationInternal API to by-pass the IOperation feature flag check. return model.GetOperationInternal(node); } } From 715e6d7262e282aba860cd410755a024355926a5 Mon Sep 17 00:00:00 2001 From: Manish Vasani Date: Tue, 14 Mar 2017 17:21:25 -0700 Subject: [PATCH 3/3] Don't assert for OperationKind.None in OperationTreeVerifier --- .../Utilities/Portable/Compilation/OperationTreeVerifier.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs index 5e36971a2248b..dbdacbf4e69d2 100644 --- a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs +++ b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs @@ -219,7 +219,8 @@ private void VisitInstanceExpression(IOperation instance) internal override void VisitNoneOperation(IOperation operation) { - Assert.True(false, "Encountered an IOperation with `Kind == OperationKind.None` while walking the operation tree."); + LogString("IOperation: "); + LogCommonPropertiesAndNewLine(operation); } public override void VisitBlockStatement(IBlockStatement operation)