From 38322d4820dfc0777a92760585b8b636f4d5c4f5 Mon Sep 17 00:00:00 2001 From: Shyam N Date: Thu, 4 May 2017 15:05:59 -0700 Subject: [PATCH] Fix VB partial method instrumentation. --- .../Portable/CodeGen/EmitExpression.vb | 19 +- .../DynamicInstrumentationTests.vb | 177 +++++++++++++++++- 2 files changed, 187 insertions(+), 9 deletions(-) diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/EmitExpression.vb b/src/Compilers/VisualBasic/Portable/CodeGen/EmitExpression.vb index 0857acb3850..fa2f527d005 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/EmitExpression.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/EmitExpression.vb @@ -1,18 +1,13 @@ ' 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 System -Imports System.Collections.Generic Imports System.Collections.Immutable -Imports System.Diagnostics -Imports System.Linq Imports System.Reflection.Metadata Imports Microsoft.CodeAnalysis.CodeGen Imports Microsoft.CodeAnalysis.VisualBasic.Symbols -Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen - Friend Partial Class CodeGenerator + Partial Friend Class CodeGenerator Private _recursionDepth As Integer Private Class EmitCancelledException @@ -2205,7 +2200,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen Debug.Assert(node.Method.IsDefinition) Debug.Assert(node.Type.SpecialType = SpecialType.System_Int32) _builder.EmitOpCode(ILOpCode.Ldtoken) - EmitSymbolToken(node.Method, node.Syntax, encodeAsRawDefinitionToken:=True) + + ' For partial methods, we emit pseudo token based on the symbol for the partial + ' definition part as opposed to the symbol for the partial implementation part. + ' We will need to resolve the symbol associated with each pseudo token in order + ' to compute the real method definition tokens later. For partial methods, this + ' resolution can only succeed if the associated symbol is the symbol for the + ' partial definition and not the symbol for the partial implementation (see + ' MethodSymbol.ResolvedMethodImpl()). + Dim symbol = If(node.Method.PartialDefinitionPart, node.Method) + + EmitSymbolToken(symbol, node.Syntax, encodeAsRawDefinitionToken:=True) End Sub Private Sub EmitMaximumMethodDefIndexExpression(node As BoundMaximumMethodDefIndex) diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/DynamicAnalysis/DynamicInstrumentationTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/DynamicAnalysis/DynamicInstrumentationTests.vb index eecd8ec2417..89023dcc6d7 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/DynamicAnalysis/DynamicInstrumentationTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/DynamicAnalysis/DynamicInstrumentationTests.vb @@ -7,8 +7,6 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.Test.Utilities.VBInstrumentationChecker Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests -Imports Roslyn.Test.Utilities -Imports Xunit Namespace Microsoft.CodeAnalysis.VisualBasic.DynamicAnalysis.UnitTests @@ -2368,6 +2366,173 @@ End Class AssertInstrumented(verifier, "D.M") End Sub + + Public Sub TestPartialMethodsWithImplementation() + Dim testSource = + 0 + Console.WriteLine("Method1: x > 0") + Method1(0) + ElseIf x < 0 + Console.WriteLine("Method1: x < 0") + End If + End Sub +End Class + +Module Program + Public Sub Main() + Test() + Microsoft.CodeAnalysis.Runtime.Instrumentation.FlushPayload() + End Sub + + Sub Test() + Console.WriteLine("Test") + Dim c = new Class1() + c.Method2(1) + End Sub +End Module +]]> + + + Dim source = + <%= testSource %> + <%= InstrumentationHelperSource %> + + + Dim checker = New VBInstrumentationChecker() + checker.Method(1, 1, "New", expectBodySpan:=False) + checker.Method(2, 1, "Private Sub Method1(x as Integer)"). + True("Console.WriteLine(""Method1: x = {0}"", x)"). + True("Console.WriteLine(""Method1: x > 0"")"). + True("Method1(0)"). + False("Console.WriteLine(""Method1: x < 0"")"). + True("x < 0"). + True("x > 0") + checker.Method(3, 1, "Public Sub Method2(x as Integer)"). + True("Console.WriteLine(""Method2: x = {0}"", x)"). + True("Method1(x)") + checker.Method(4, 1, "Public Sub Main()"). + True("Test()"). + True("Microsoft.CodeAnalysis.Runtime.Instrumentation.FlushPayload()") + checker.Method(5, 1, "Sub Test()"). + True("Console.WriteLine(""Test"")"). + True("new Class1()"). + True("c.Method2(1)") + checker.Method(8, 1). + True(). + False(). + True(). + True(). + True(). + True(). + True(). + True(). + True(). + True(). + True() + + Dim expectedOutput = "Test +Method2: x = 1 +Method1: x = 1 +Method1: x > 0 +Method1: x = 0 +" + XCDataToString(checker.ExpectedOutput) + + Dim verifier = CompileAndVerify(source, expectedOutput, options:=TestOptions.ReleaseExe) + checker.CompleteCheck(verifier.Compilation, testSource) + verifier.VerifyDiagnostics() + + verifier = CompileAndVerify(source, expectedOutput, options:=TestOptions.DebugExe) + checker.CompleteCheck(verifier.Compilation, testSource) + verifier.VerifyDiagnostics() + End Sub + + + Public Sub TestPartialMethodsWithoutImplementation() + Dim testSource = + + + + Dim source = + <%= testSource %> + <%= InstrumentationHelperSource %> + + + Dim checker = New VBInstrumentationChecker() + checker.Method(1, 1, "New", expectBodySpan:=False) + checker.Method(2, 1, "Public Sub Method2(x as Integer)"). + True("Console.WriteLine(""Method2: x = {0}"", x)") + checker.Method(3, 1, "Public Sub Main()"). + True("Test()"). + True("Microsoft.CodeAnalysis.Runtime.Instrumentation.FlushPayload()") + checker.Method(4, 1, "Sub Test()"). + True("Console.WriteLine(""Test"")"). + True("new Class1()"). + True("c.Method2(1)") + checker.Method(7, 1). + True(). + False(). + True(). + True(). + True(). + True(). + True(). + True(). + True(). + True(). + True() + + Dim expectedOutput = "Test +Method2: x = 1 +" + XCDataToString(checker.ExpectedOutput) + + Dim verifier = CompileAndVerify(source, expectedOutput, options:=TestOptions.ReleaseExe) + checker.CompleteCheck(verifier.Compilation, testSource) + verifier.VerifyDiagnostics() + + verifier = CompileAndVerify(source, expectedOutput, options:=TestOptions.DebugExe) + checker.CompleteCheck(verifier.Compilation, testSource) + verifier.VerifyDiagnostics() + End Sub + Private Shared Sub AssertNotInstrumented(verifier As CompilationVerifier, qualifiedMethodName As String) AssertInstrumented(verifier, qualifiedMethodName, expected:=False) End Sub @@ -2394,6 +2559,14 @@ End Class emitOptions:=EmitOptions.Default.WithInstrumentationKinds(ImmutableArray.Create(InstrumentationKind.TestCoverage))) End Function + Private Overloads Function CompileAndVerify(source As XElement, Optional expectedOutput As String = Nothing, Optional options As VisualBasicCompilationOptions = Nothing) As CompilationVerifier + Return CompileAndVerify(source, + LatestVbReferences, + expectedOutput, + options:=If(options, TestOptions.ReleaseExe).WithDeterministic(True), + emitOptions:=EmitOptions.Default.WithInstrumentationKinds(ImmutableArray.Create(InstrumentationKind.TestCoverage))) + End Function + Private Overloads Function CompileAndVerify(source As String, Optional expectedOutput As String = Nothing, Optional options As VisualBasicCompilationOptions = Nothing) As CompilationVerifier Return CompileAndVerify(source, LatestVbReferences, -- GitLab