/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/InstructionDecoderTests.vb
674 строки
25 KB
Cyrus Najmabadi
Organize VB imports
27 июн 2025, 21:53
27 июн 2025, 21:53
e9c47fd
Код
Авторство
О чём код?
' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.ExpressionEvaluator Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests Imports Microsoft.VisualStudio.Debugger.Evaluation Imports Roslyn.Test.Utilities Imports Xunit Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.UnitTests '// TODO: constructors '// TODO: keyword identifiers '// TODO: containing type and parameter types that are nested types '// TODO: anonymous methods '// TODO: iterator/async lambda '// TODO: parameter generic(Of generic) '// TODO: generic state machines (generic source method/source type) '// TODO: string argument values '// TODO: string argument values requiring quotes '// TODO: argument flags == names only, types only, values only '// TODO: generic class/method with 2 or more type parameters '// TODO: generic argument type that is not from a referenced assembly Public Class InstructionDecoderTests : Inherits ExpressionCompilerTestBase <Fact> Public Sub GetNameArgumentCounts() Dim source = " Imports System Module Module1 Sub NoArgs() End Sub Sub OneArg(one As Int32) End Sub Sub TwoArgs(one As Object, two As Exception) End Sub End Module" Assert.Equal( "Module1.NoArgs()", GetName(source, "Module1.NoArgs", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) Assert.Equal( "Module1.OneArg(Integer one)", GetName(source, "Module1.OneArg", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) Assert.Equal( "Module1.TwoArgs(Object one, System.Exception two)", GetName(source, "Module1.TwoArgs", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) End Sub <Fact> Public Sub GetNameNullable() Dim source = " Imports System Module Module1 Sub M1(n As Nullable(Of Int32)) End Sub Sub M2(n As Int64?) End Sub End Module" Assert.Equal( "Module1.M1(Integer? n)", GetName(source, "Module1.M1", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) Assert.Equal( "Module1.M2(Long? n)", GetName(source, "Module1.M2", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) End Sub <Fact> Public Sub GetNameGenerics() Dim source = " Imports System Class Class1(Of T) Sub M1(Of U)(a As Action(Of Int32)) End Sub Sub M2(Of U)(a As Action(Of T)) End Sub Sub M3(Of U)(a As Action(Of U)) End Sub End Class" Assert.Equal( "Class1(Of T).M1(Of U)(System.Action(Of Integer) a)", GetName(source, "Class1.M1", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) Assert.Equal( "Class1(Of T).M2(Of U)(System.Action(Of T) a)", GetName(source, "Class1.M2", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) Assert.Equal( "Class1(Of T).M3(Of U)(System.Action(Of U) a)", GetName(source, "Class1.M3", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) Assert.Equal( "Class1(Of String).M1(Of Decimal)(System.Action(Of Integer) a)", GetName(source, "Class1.M1", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={GetType(String), GetType(Decimal)})) Assert.Equal( "Class1(Of String).M2(Of Decimal)(System.Action(Of String) a)", GetName(source, "Class1.M2", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={GetType(String), GetType(Decimal)})) Assert.Equal( "Class1(Of String).M3(Of Decimal)(System.Action(Of Decimal) a)", GetName(source, "Class1.M3", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={GetType(String), GetType(Decimal)})) End Sub <Fact> Public Sub GetNameNullTypeArguments() Dim source = " Imports System Class Class1(Of T) Sub M(Of U)(a As Action(Of U)) End Sub End Class" Assert.Equal( "Class1(Of T).M(Of U)(System.Action(Of U) a)", GetName(source, "Class1.M", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:=New Type() {Nothing, Nothing})) Assert.Equal( "Class1(Of T).M(Of U)(System.Action(Of U) a)", GetName(source, "Class1.M", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={GetType(String), Nothing})) Assert.Equal( "Class1(Of T).M(Of U)(System.Action(Of U) a)", GetName(source, "Class1.M", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={Nothing, GetType(Decimal)})) End Sub <Fact> Public Sub GetNameGenericArgumentTypeNotInReferences() Dim source = " Class Class1 End Class" Dim serializedTypeArgumentName = "Class1, " & NameOf(InstructionDecoderTests) & ", Culture=neutral, PublicKeyToken=null" Assert.Equal( "System.Collections.Generic.Comparer(Of Class1).Create(System.Comparison(Of Class1) comparison)", GetName(source, "System.Collections.Generic.Comparer.Create", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={serializedTypeArgumentName})) End Sub <Fact> Public Sub GetNameAsync() Dim source = " Imports System.Threading.Tasks Module Module1 Async Function M() As Task Await MAsync() End Function Async Function MAsync() As Task(Of Integer) Return 3 End Function End Module" Assert.Equal( "Module1.M()", GetName(source, "Module1.VB$StateMachine_0_M.MoveNext", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) End Sub <Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1107977")> Public Sub GetNameGenericAsync() Dim source = " Imports System.Threading.Tasks Class C Shared Async Function M(Of T)(x As T) As Task(Of T) Await Task.Yield() Return x End Function End Class" Assert.Equal( "C.M(Of Long)(Long x)", GetName(source, "C.VB$StateMachine_1_M.MoveNext", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={GetType(Long)})) End Sub <Fact> Public Sub GetNameIterator() Dim source = " Imports System.Collections.Generic Module Module1 Iterator Function M() As IEnumerable(Of Integer) Yield 1 Yield 3 Yield 5 Yield 7 End Function End Module" Assert.Equal( "Module1.M()", GetName(source, "Module1.VB$StateMachine_0_M.MoveNext", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) End Sub <Fact> Public Sub GetNameLambda() Dim source = " Module Module1 Sub M() Dim f = Function() 3 End Sub End Module" Assert.Equal( "Module1.<closure>.<lambda0-0>()", GetName(source, "Module1._Closure$__._Lambda$__0-0", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) End Sub <Fact> Public Sub GetNameGenericLambda() Dim source = " Imports System Class Class1(Of T) Sub M(Of U As T)() Dim f As Func(Of U, T) = Function(u2 As U) u2 End Sub End Class" Assert.Equal( "Class1(Of System.Exception).<closure>.<lambda1-0>(System.ArgumentException u2)", GetName(source, "Class1._Closure$__1._Lambda$__1-0", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={GetType(Exception), GetType(ArgumentException)})) End Sub <Fact> Public Sub GetNameOptionalParameter() Dim source = " Module Module1 Function M(Optional d As Date = #1/1/1970#) As Integer Return 42 End Function End Module" Assert.Equal( "Module1.M(Date d)", GetName(source, "Module1.M", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) Assert.Equal( "Module1.M(Date d = #6/23/1912#)", GetName(source, "Module1.M", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, argumentValues:={"#6/23/1912#"})) End Sub <Fact> Public Sub GetNameProperties() Dim source = " Class Class1 Property P As Integer Get Return 1 End Get Set End Set End Property Default Property D(x As Object) As Integer Get Return 42 End Get Set(i As Integer) End Set End Property End Class" Assert.Equal( "Class1.get_P()", GetName(source, "Class1.get_P", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) Assert.Equal( "Class1.set_P(Integer Value)", GetName(source, "Class1.set_P", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) Assert.Equal( "Class1.get_D(Object x)", GetName(source, "Class1.get_D", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) Assert.Equal( "Class1.set_D(Object x, Integer i)", GetName(source, "Class1.set_D", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) End Sub <Fact> Public Sub GetNameInterfaceImplementation() Dim source = " Imports System Class C : Implements IDisposable Sub Dispoze() Implements IDisposable.Dispose End Sub End Class" Assert.Equal( "C.Dispoze()", GetName(source, "C.Dispoze", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) End Sub <Fact> Public Sub GetNameExtensionMethod() Dim source = " Imports System.Runtime.CompilerServices Module Extensions <Extension> Sub M([Me] As String) End Sub End Module" Assert.Equal( "Extensions.M(String Me)", GetName(source, "Extensions.M", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) End Sub <Fact> Public Sub GetNameArgumentFlagsNone() Dim source = " Module Module1 Sub M1() End Sub Sub M2(x, y) End Sub End Module" Assert.Equal( "Module1.M1", GetName(source, "Module1.M1", DkmVariableInfoFlags.None)) Assert.Equal( "Module1.M2", GetName(source, "Module1.M2", DkmVariableInfoFlags.None)) End Sub <Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1107978")> Public Sub GetNameRefAndOutParameters() Dim source = " Imports System.Runtime.InteropServices Class C Shared Sub M(ByRef x As Integer, <Out> ByRef y As Integer) y = x End Sub End Class" Assert.Equal( "C.M", GetName(source, "C.M", DkmVariableInfoFlags.None)) Assert.Equal( "C.M(1, 2)", GetName(source, "C.M", DkmVariableInfoFlags.None, argumentValues:={"1", "2"})) Assert.Equal( "C.M(Integer, Integer)", GetName(source, "C.M", DkmVariableInfoFlags.Types)) Assert.Equal( "C.M(x, y)", GetName(source, "C.M", DkmVariableInfoFlags.Names)) Assert.Equal( "C.M(Integer x, Integer y)", GetName(source, "C.M", DkmVariableInfoFlags.Types Or DkmVariableInfoFlags.Names)) End Sub <Fact> Public Sub GetNameParamsParameters() Dim source = " Class C Shared Sub M(ParamArray x() As Integer) End Sub End Class" Assert.Equal( "C.M(Integer() x)", GetName(source, "C.M", DkmVariableInfoFlags.Types Or DkmVariableInfoFlags.Names)) End Sub <Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1154945")> Public Sub GetNameIncorrectNumberOfArgumentValues() Dim source = " Class C Sub M(x As Integer, y As Integer) End Sub End Class" Dim expected = "C.M(Integer x, Integer y)" Assert.Equal(expected, GetName(source, "C.M", DkmVariableInfoFlags.Types Or DkmVariableInfoFlags.Names, argumentValues:={})) Assert.Equal(expected, GetName(source, "C.M", DkmVariableInfoFlags.Types Or DkmVariableInfoFlags.Names, argumentValues:={"1"})) Assert.Equal(expected, GetName(source, "C.M", DkmVariableInfoFlags.Types Or DkmVariableInfoFlags.Names, argumentValues:={"1", "2", "3"})) End Sub <Fact> Public Sub GetReturnTypeNamePrimitive() Dim source = " Class C Function M1() As UInteger Return 42 End Function End Class" Assert.Equal("UInteger", GetReturnTypeName(source, "C.M1")) End Sub <Fact> Public Sub GetReturnTypeNameNested() Dim source = " Class C Function M1() As N.D.E Return Nothing End Function End Class Namespace N Class D Friend Structure E End Structure End Class End Namespace" Assert.Equal("N.D.E", GetReturnTypeName(source, "C.M1")) End Sub <Fact> Public Sub GetReturnTypeNameGenericOfPrimitive() Dim source = " Imports System Class C Function M1() As Action(Of Int32) Return Nothing End Function End Class" Assert.Equal("System.Action(Of Integer)", GetReturnTypeName(source, "C.M1")) End Sub <Fact> Public Sub GetReturnTypeNameGenericOfNested() Dim source = " Imports System Class C Function M1() As Action(Of D) Return Nothing End Function Class D End Class End Class" Assert.Equal("System.Action(Of C.D)", GetReturnTypeName(source, "C.M1")) End Sub <Fact> Public Sub GetReturnTypeNameGenericOfGeneric() Dim source = " Imports System Class C Function M1(Of T)() As Action(Of Func(Of T)) Return Nothing End Function End Class" Assert.Equal("System.Action(Of System.Func(Of Object))", GetReturnTypeName(source, "C.M1", typeArguments:={GetType(Object)})) End Sub <Fact> Public Sub GetCompactName_Members() Dim source = " Imports System Imports System.Runtime.CompilerServices Class C Shared Sub New() End Sub Sub New(x As Integer) End Sub Function F() As Object Return Nothing End Function Property P As Object Get Return Nothing End Get Set End Set End Property Default Property Item(i As Integer) As Object Get Return Nothing End Get Set End Set End Property Event E As EventHandler Shared Operator +(c As C) As C Return Nothing End Operator Shared Widening Operator CType(c As C) As String Return Nothing End Operator End Class Module E <Extension> Sub M(x As String) End Sub End Module" Dim compilation = CreateCompilation(source) Dim containingType = compilation.GlobalNamespace.GetTypeMember("C") VerifyMethodName(compilation, containingType.GetMethod("F"), "C.F()", "F") VerifyMethodName(compilation, containingType.GetMethod("get_P"), "C.get_P()", "P") VerifyMethodName(compilation, containingType.GetMethod("set_P"), "C.set_P(Value)", "P") VerifyMethodName(compilation, containingType.GetMethod("get_Item"), "C.get_Item(i)", "Item") VerifyMethodName(compilation, containingType.GetMethod("set_Item"), "C.set_Item(i, Value)", "Item") VerifyMethodName(compilation, containingType.GetMethod("add_E"), "C.E(obj)", "E") VerifyMethodName(compilation, containingType.GetMethod("remove_E"), "C.E(obj)", "E") VerifyMethodName(compilation, containingType.GetMethod(".cctor"), "C.New()", "New") VerifyMethodName(compilation, containingType.GetMethod(".ctor"), "C.New(x)", "New") VerifyMethodName(compilation, containingType.GetMethod("op_UnaryPlus"), "C.+(c)", "+") VerifyMethodName(compilation, containingType.GetMethod("op_Implicit"), "C.CType(c)", "CType") VerifyMethodName(compilation, compilation.GlobalNamespace.GetTypeMember("E").GetMethod("M"), "E.M(x)", "M") End Sub <Fact> Public Sub GetCompactName_GenericMethod() Dim source = " Imports System Class A(Of T) Public Structure B(Of U) Sub M(Of V)(x As T, y As U, z As V) End Sub End Structure End Class" Dim compilation = CreateCompilation(source) Dim instructionDecoder = VisualBasicInstructionDecoder.Instance Dim method = GetConstructedMethod( compilation, DirectCast(compilation.GlobalNamespace.GetTypeMember("A").GetTypeMember("B").GetMethod("M"), PEMethodSymbol), {"Object", "Integer", "String"}, instructionDecoder) Dim actualName = instructionDecoder.GetName(method, includeParameterTypes:=False, includeParameterNames:=True) Dim actualCompactName = instructionDecoder.GetCompactName(method) Assert.Equal("A(Of Object).B(Of Integer).M(Of String)(x, y, z)", actualName) Assert.Equal("M", actualCompactName) End Sub <Fact> Public Sub GetCompactName_ExplicitImplementation() Dim source = " Imports System Interface I Function F() As Object Property P As Object Default ReadOnly Property Item(i As Integer) As Object End Interface Class C Implements I Function I_F0() As Object Implements I.F Return Nothing End Function Property I_P0 As Object Implements I.P Get Return Nothing End Get Set End Set End Property Default ReadOnly Property I_Item0(i As Integer) As Object Implements I.Item Get Return Nothing End Get End Property End Class" Dim compilation = CreateCompilation(source) Dim containingType = compilation.GlobalNamespace.GetTypeMember("C") VerifyMethodName(compilation, containingType.GetMethod("I_F0"), "C.I_F0()", "I_F0") VerifyMethodName(compilation, containingType.GetMethod("get_I_P0"), "C.get_I_P0()", "I_P0") VerifyMethodName(compilation, containingType.GetMethod("set_I_P0"), "C.set_I_P0(Value)", "I_P0") VerifyMethodName(compilation, containingType.GetMethod("get_I_Item0"), "C.get_I_Item0(i)", "I_Item0") End Sub Private Sub VerifyMethodName(compilation As VisualBasicCompilation, method As MethodSymbol, expectedName As String, expectedCompactName As String) Dim instructionDecoder = VisualBasicInstructionDecoder.Instance method = GetConstructedMethod( compilation, DirectCast(method, PEMethodSymbol), Nothing, instructionDecoder) Dim actualName = instructionDecoder.GetName(method, includeParameterTypes:=False, includeParameterNames:=True) Dim actualCompactName = instructionDecoder.GetCompactName(method) Assert.Equal(expectedName, actualName) Assert.Equal(expectedCompactName, actualCompactName) End Sub Private Function GetName(source As String, methodName As String, argumentFlags As DkmVariableInfoFlags, Optional typeArguments() As Type = Nothing, Optional argumentValues() As String = Nothing) As String Dim serializedTypeArgumentNames = typeArguments?.Select(Function(t) t?.AssemblyQualifiedName).ToArray() Return GetName(source, methodName, argumentFlags, serializedTypeArgumentNames, argumentValues) End Function Private Function GetName(source As String, methodName As String, argumentFlags As DkmVariableInfoFlags, typeArguments() As String, Optional argumentValues() As String = Nothing) As String Debug.Assert((argumentFlags And (DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) = argumentFlags, "Unexpected argumentFlags", "argumentFlags = {0}", argumentFlags) Dim instructionDecoder = VisualBasicInstructionDecoder.Instance Dim compilation = CreateCompilation(source) Dim method = GetConstructedMethod( compilation, DirectCast(GetMethodOrTypeBySignature(compilation, methodName), PEMethodSymbol), typeArguments, instructionDecoder) Dim includeParameterTypes = argumentFlags.Includes(DkmVariableInfoFlags.Types) Dim includeParameterNames = argumentFlags.Includes(DkmVariableInfoFlags.Names) Dim builder As ArrayBuilder(Of String) = Nothing If argumentValues IsNot Nothing Then builder = ArrayBuilder(Of String).GetInstance() builder.AddRange(argumentValues) End If Dim name = instructionDecoder.GetName(method, includeParameterTypes, includeParameterNames, builder) If builder IsNot Nothing Then builder.Free() End If Return name End Function Private Function CreateCompilation(source As String) As VisualBasicCompilation Dim compilation = CreateEmptyCompilationWithReferences( {VisualBasicSyntaxTree.ParseText(source)}, references:={MscorlibRef_v4_0_30316_17626, MsvbRef_v4_0_30319_17929}, options:=TestOptions.DebugDll, assemblyName:=NameOf(InstructionDecoderTests)) Dim runtime = CreateRuntimeInstance(compilation) Dim moduleInstances = runtime.Modules Dim blocks = moduleInstances.SelectAsArray(Function(m) m.MetadataBlock) Return blocks.ToCompilation() End Function Private Function GetReturnTypeName(source As String, methodName As String, Optional typeArguments() As Type = Nothing) As String Dim instructionDecoder = VisualBasicInstructionDecoder.Instance Dim serializedTypeArgumentNames = typeArguments?.Select(Function(t) t?.AssemblyQualifiedName).ToArray() Dim compilation = CreateCompilation(source) Dim method = GetConstructedMethod( compilation, DirectCast(GetMethodOrTypeBySignature(compilation, methodName), PEMethodSymbol), serializedTypeArgumentNames, instructionDecoder) Return instructionDecoder.GetReturnTypeName(method) End Function Private Function GetConstructedMethod(compilation As VisualBasicCompilation, frame As PEMethodSymbol, serializedTypeArgumentNames() As String, instructionDecoder As VisualBasicInstructionDecoder) As MethodSymbol ' Once we have the method token, we want to look up the method (again) ' using the same helper as the product code. This helper will also map ' async/ iterator "MoveNext" methods to the original source method. Dim method As MethodSymbol = compilation.GetSourceMethod( New ModuleId(DirectCast(frame.ContainingModule, PEModuleSymbol).Module.GetModuleVersionIdOrThrow(), frame.ContainingModule.Name), frame.Handle) If serializedTypeArgumentNames IsNot Nothing Then Assert.NotEmpty(serializedTypeArgumentNames) Dim typeParameters = instructionDecoder.GetAllTypeParameters(method) Assert.NotEmpty(typeParameters) ' Use the same helper method as the FrameDecoder to get the TypeSymbols for the ' generic type arguments (rather than using EETypeNameDecoder directly). Dim typeArgumentSymbols = instructionDecoder.GetTypeSymbols(compilation, method, serializedTypeArgumentNames) If Not typeArgumentSymbols.IsEmpty Then method = instructionDecoder.ConstructMethod(method, typeParameters, typeArgumentSymbols) End If End If Return method End Function End Class End Namespace