|
' 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 System.Collections.Immutable
Imports System.IO
Imports System.Threading
Imports Microsoft.CodeAnalysis.Debugging
Imports Microsoft.CodeAnalysis.ExpressionEvaluator
Imports Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests
Imports Roslyn.Test.PdbUtilities
Imports Roslyn.Test.Utilities
Imports Xunit
Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.UnitTests
Public Class DteeTests
Inherits ExpressionCompilerTestBase
Private Const s_dteeEntryPointSource = "
Imports System.Collections
Class HostProc
Sub BreakForDebugger()
End Sub
End Class
"
Private Const s_dteeEntryPointName = "HostProc.BreakForDebugger"
<Fact>
Public Sub IsDteeEntryPoint()
Const source = "
Class HostProc
Sub BreakForDebugger()
End Sub
End Class
Class AppDomain
Sub ExecuteAssembly()
End Sub
End Class
"
Dim comp = CreateCompilationWithMscorlib40({source})
Dim [global] = comp.GlobalNamespace
Dim m1 = [global].GetMember(Of NamedTypeSymbol)("HostProc").GetMember(Of MethodSymbol)("BreakForDebugger")
Dim m2 = [global].GetMember(Of NamedTypeSymbol)("AppDomain").GetMember(Of MethodSymbol)("ExecuteAssembly")
Assert.True(EvaluationContext.IsDteeEntryPoint(m1))
Assert.True(EvaluationContext.IsDteeEntryPoint(m2))
End Sub
<Fact>
Public Sub IsDteeEntryPoint_Namespace()
Const source = "
Namespace N
Class HostProc
Sub BreakForDebugger()
End Sub
End Class
Class AppDomain
Sub ExecuteAssembly()
End Sub
End Class
End Namespace
"
Dim comp = CreateCompilationWithMscorlib40({source})
Dim [namespace] = comp.GlobalNamespace.GetMember(Of NamespaceSymbol)("N")
Dim m1 = [namespace].GetMember(Of NamedTypeSymbol)("HostProc").GetMember(Of MethodSymbol)("BreakForDebugger")
Dim m2 = [namespace].GetMember(Of NamedTypeSymbol)("AppDomain").GetMember(Of MethodSymbol)("ExecuteAssembly")
Assert.True(EvaluationContext.IsDteeEntryPoint(m1))
Assert.True(EvaluationContext.IsDteeEntryPoint(m2))
End Sub
<Fact>
Public Sub IsDteeEntryPoint_CaseSensitive()
Const source = "
Namespace N1
Class HostProc
Sub breakfordebugger()
End Sub
End Class
Class AppDomain
Sub executeassembly()
End Sub
End Class
End Namespace
Namespace N2
Class hostproc
Sub BreakForDebugger()
End Sub
End Class
Class appdomain
Sub ExecuteAssembly()
End Sub
End Class
End Namespace
"
Dim comp = CreateCompilationWithMscorlib40({source})
Dim [global] = comp.GlobalNamespace
Dim [namespace] = [global].GetMember(Of NamespaceSymbol)("N1")
Dim m1 = [namespace].GetMember(Of NamedTypeSymbol)("HostProc").GetMember(Of MethodSymbol)("BreakForDebugger")
Dim m2 = [namespace].GetMember(Of NamedTypeSymbol)("AppDomain").GetMember(Of MethodSymbol)("ExecuteAssembly")
Assert.False(EvaluationContext.IsDteeEntryPoint(m1))
Assert.False(EvaluationContext.IsDteeEntryPoint(m2))
[namespace] = [global].GetMember(Of NamespaceSymbol)("N2")
m1 = [namespace].GetMember(Of NamedTypeSymbol)("HostProc").GetMember(Of MethodSymbol)("BreakForDebugger")
m2 = [namespace].GetMember(Of NamedTypeSymbol)("AppDomain").GetMember(Of MethodSymbol)("ExecuteAssembly")
Assert.False(EvaluationContext.IsDteeEntryPoint(m1))
Assert.False(EvaluationContext.IsDteeEntryPoint(m2))
End Sub
<Fact>
Public Sub DteeEntryPointImportsIgnored()
Dim comp = CreateCompilationWithMscorlib40({s_dteeEntryPointSource}, options:=TestOptions.DebugDll, assemblyName:=GetUniqueName())
WithRuntimeInstance(comp, {MscorlibRef},
Sub(runtime)
Dim lazyAssemblyReaders = MakeLazyAssemblyReaders(runtime)
Dim evalContext = CreateMethodContext(runtime, s_dteeEntryPointName, lazyAssemblyReaders:=lazyAssemblyReaders)
Dim compContext = evalContext.CreateCompilationContext(withSyntax:=True)
Dim rootNamespace As NamespaceSymbol = Nothing
Dim currentNamespace As NamespaceSymbol = Nothing
Dim typesAndNamespaces As ImmutableArray(Of NamespaceOrTypeAndImportsClausePosition) = Nothing
Dim aliases As Dictionary(Of String, AliasAndImportsClausePosition) = Nothing
Dim xmlNamespaces As Dictionary(Of String, XmlNamespaceAndImportsClausePosition) = Nothing
ImportsDebugInfoTests.GetImports(compContext, rootNamespace, currentNamespace, typesAndNamespaces, aliases, xmlNamespaces)
Assert.Equal("", rootNamespace.Name)
Assert.Equal("", currentNamespace.Name)
Assert.True(typesAndNamespaces.IsDefault)
Assert.Null(aliases)
Assert.Null(xmlNamespaces)
End Sub)
End Sub
<Fact>
Public Sub ImportStrings_DefaultNamespaces()
Dim source1 = "
Class C1
Sub M() ' Need a method to which we can attach import custom debug info.
End Sub
End Class
"
Dim source2 = "
Class C2
Sub M() ' Need a method to which we can attach import custom debug info.
End Sub
End Class
"
Dim module1 = CreateCompilationWithMscorlib40({source1}, options:=TestOptions.DebugDll.WithRootNamespace("root1")).ToModuleInstance()
Dim module2 = CreateCompilationWithMscorlib40({source2}, options:=TestOptions.DebugDll.WithRootNamespace("root2")).ToModuleInstance()
Dim runtimeInstance = CreateRuntimeInstance({module1, module2, MscorlibRef.ToModuleInstance()})
Dim methodDebugInfo = EvaluationContext.SynthesizeMethodDebugInfoForDtee(MakeAssemblyReaders(runtimeInstance))
CheckDteeMethodDebugInfo(methodDebugInfo, "root1", "root2")
End Sub
<Fact>
Public Sub ImportStrings_ModuleNamespaces()
Dim source1 = "
Namespace N1
Module M
End Module
End Namespace
Namespace N2
Namespace N3
Module M
End Module
End Namespace
End Namespace
Namespace N4
Class C
End Class
End Namespace
"
Dim source2 = "
Namespace N1 ' Also imported for source1
Module M2
End Module
End Namespace
Namespace N5
Namespace N6
Module M
End Module
End Namespace
End Namespace
Namespace N7
Class C
End Class
End Namespace
"
Dim module1 = CreateCompilationWithMscorlib40({source1}, {MsvbRef}, options:=TestOptions.DebugDll).ToModuleInstance()
Dim module2 = CreateCompilationWithMscorlib40({source2}, {MsvbRef}, options:=TestOptions.DebugDll).ToModuleInstance()
Dim runtimeInstance = CreateRuntimeInstance({module1, module2, MscorlibRef.ToModuleInstance(), MsvbRef.ToModuleInstance()})
Dim methodDebugInfo = EvaluationContext.SynthesizeMethodDebugInfoForDtee(MakeAssemblyReaders(runtimeInstance))
CheckDteeMethodDebugInfo(methodDebugInfo, "N1", "N2.N3", "N5.N6")
End Sub
<Fact>
Public Sub ImportStrings_NoMethods()
Dim comp = CreateCompilationWithMscorlib40({""}, {MsvbRef}, options:=TestOptions.DebugDll.WithRootNamespace("root"), assemblyName:=GetUniqueName())
WithRuntimeInstance(comp, {MscorlibRef, MsvbRef},
Sub(runtime)
' Since there are no methods in the assembly, there is no import custom debug info, so we
' have no way to find the root namespace.
Dim methodDebugInfo = EvaluationContext.SynthesizeMethodDebugInfoForDtee(MakeAssemblyReaders(runtime))
CheckDteeMethodDebugInfo(methodDebugInfo)
End Sub)
End Sub
<Fact>
Public Sub ImportStrings_IgnoreAssemblyWithoutPdb()
Dim source1 = "
Namespace N1
Module M
End Module
End Namespace
"
Dim source2 = "
Namespace N2
Module M
End Module
End Namespace
"
Dim comp1 = CreateCompilationWithMscorlib40({source1}, {MsvbRef}, options:=TestOptions.ReleaseDll)
Dim module1 = comp1.ToModuleInstance(debugFormat:=Nothing)
Dim comp2 = CreateCompilationWithMscorlib40({source2}, {MsvbRef}, options:=TestOptions.DebugDll)
Dim module2 = comp2.ToModuleInstance()
Dim runtimeInstance = CreateRuntimeInstance({
module1,
module2,
MscorlibRef.ToModuleInstance(),
MsvbRef.ToModuleInstance()})
Dim methodDebugInfo = EvaluationContext.SynthesizeMethodDebugInfoForDtee(MakeAssemblyReaders(runtimeInstance))
CheckDteeMethodDebugInfo(methodDebugInfo, "N2")
End Sub
<Fact>
Public Sub FalseModule_Nested()
' NOTE: VB only allows top-level module types.
Dim ilSource = "
.assembly extern Microsoft.VisualBasic { }
.class public auto ansi N1.Outer
extends [mscorlib]System.Object
{
.class auto ansi nested public sealed Inner
extends [mscorlib]System.Object
{
.custom instance void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute::.ctor()
= {}
.method public specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
} // end of class Inner
.method public specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
} // end of class N1.Outer
"
Dim ilModule = ExpressionCompilerTestHelpers.GetModuleInstanceForIL(ilSource)
Dim runtime = CreateRuntimeInstance(ilModule, {MscorlibRef, MsvbRef})
Dim methodDebugInfo = EvaluationContext.SynthesizeMethodDebugInfoForDtee(MakeAssemblyReaders(runtime))
CheckDteeMethodDebugInfo(methodDebugInfo)
End Sub
<Fact>
Public Sub FalseModule_Generic()
' NOTE: VB only allows non-generic module types.
Dim ilSource = "
.assembly extern Microsoft.VisualBasic { }
.class public auto ansi sealed N1.M`1<T>
extends [mscorlib]System.Object
{
.custom instance void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute::.ctor()
= {}
} // end of class M
"
Dim ilModule = ExpressionCompilerTestHelpers.GetModuleInstanceForIL(ilSource)
Dim runtime = CreateRuntimeInstance(ilModule, {MscorlibRef, MsvbRef})
Dim methodDebugInfo = EvaluationContext.SynthesizeMethodDebugInfoForDtee(MakeAssemblyReaders(runtime))
CheckDteeMethodDebugInfo(methodDebugInfo)
End Sub
<Fact>
Public Sub FalseModule_Interface()
' NOTE: VB only allows non-interface module types.
Dim ilSource = "
.assembly extern Microsoft.VisualBasic { }
.class interface private abstract auto ansi I
{
.custom instance void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute::.ctor()
= {}
} // end of class I
"
Dim ilModule = ExpressionCompilerTestHelpers.GetModuleInstanceForIL(ilSource)
Dim runtime = CreateRuntimeInstance(ilModule, {MscorlibRef, MsvbRef})
Dim methodDebugInfo = EvaluationContext.SynthesizeMethodDebugInfoForDtee(MakeAssemblyReaders(runtime))
CheckDteeMethodDebugInfo(methodDebugInfo)
End Sub
<Fact>
Public Sub ImportSymbols()
Dim source1 = "
Namespace N1
Module M
Sub M() ' Need a method to record the root namespace.
End Sub
End Module
End Namespace
Namespace N2
Module M
End Module
End Namespace
"
Dim source2 = "
Namespace N1 ' Also imported for source1
Module M2
Sub M() ' Need a method to record the root namespace.
End Sub
End Module
End Namespace
Namespace N3
Module M
End Module
End Namespace
"
Dim dteeComp = CreateCompilationWithMscorlib40({s_dteeEntryPointSource}, options:=TestOptions.DebugDll, assemblyName:=GetUniqueName())
Dim dteeModuleInstance = dteeComp.ToModuleInstance()
Dim comp1 = CreateCompilationWithMscorlib40({source1}, {MsvbRef}, options:=TestOptions.DebugDll.WithRootNamespace("root"), assemblyName:=GetUniqueName())
Dim compModuleInstance1 = comp1.ToModuleInstance()
Dim comp2 = CreateCompilationWithMscorlib40({source2}, {MsvbRef}, options:=TestOptions.DebugDll.WithRootNamespace("root"), assemblyName:=GetUniqueName())
Dim compModuleInstance2 = comp2.ToModuleInstance()
Dim runtimeInstance = CreateRuntimeInstance({
dteeModuleInstance,
compModuleInstance1,
compModuleInstance2,
MscorlibRef.ToModuleInstance(),
MsvbRef.ToModuleInstance()})
Dim lazyAssemblyReaders = MakeLazyAssemblyReaders(runtimeInstance)
Dim evalContext = CreateMethodContext(runtimeInstance, s_dteeEntryPointName, lazyAssemblyReaders:=lazyAssemblyReaders)
Dim compContext = evalContext.CreateCompilationContext(withSyntax:=True)
Dim rootNamespace As NamespaceSymbol = Nothing
Dim currentNamespace As NamespaceSymbol = Nothing
Dim typesAndNamespaces As ImmutableArray(Of NamespaceOrTypeAndImportsClausePosition) = Nothing
Dim aliases As Dictionary(Of String, AliasAndImportsClausePosition) = Nothing
Dim xmlNamespaces As Dictionary(Of String, XmlNamespaceAndImportsClausePosition) = Nothing
ImportsDebugInfoTests.GetImports(compContext, rootNamespace, currentNamespace, typesAndNamespaces, aliases, xmlNamespaces)
Assert.Equal("", rootNamespace.Name)
Assert.Equal("", currentNamespace.Name)
Assert.Null(aliases)
Assert.Null(xmlNamespaces)
AssertEx.SetEqual(typesAndNamespaces.Select(Function(tn) tn.NamespaceOrType.ToTestDisplayString()), "root", "root.N1", "root.N2", "root.N3")
End Sub
Private Shared Function MakeLazyAssemblyReaders(runtimeInstance As RuntimeInstance) As Lazy(Of ImmutableArray(Of AssemblyReaders))
Return New Lazy(Of ImmutableArray(Of AssemblyReaders))(
Function() MakeAssemblyReaders(runtimeInstance),
LazyThreadSafetyMode.None)
End Function
Private Shared Function MakeAssemblyReaders(runtimeInstance As RuntimeInstance) As ImmutableArray(Of AssemblyReaders)
Return ImmutableArray.CreateRange(runtimeInstance.Modules.
Where(Function(instance) instance.SymReader IsNot Nothing).
Select(Function(instance) New AssemblyReaders(instance.GetMetadataReader(), instance.SymReader)))
End Function
Private Shared Sub CheckDteeMethodDebugInfo(methodDebugInfo As MethodDebugInfo(Of TypeSymbol, LocalSymbol), ParamArray namespaceNames As String())
Assert.Equal("", methodDebugInfo.DefaultNamespaceName)
Dim importRecordGroups = methodDebugInfo.ImportRecordGroups
Assert.Equal(2, importRecordGroups.Length)
Dim fileLevelImportRecords As ImmutableArray(Of ImportRecord) = importRecordGroups(0)
Dim projectLevelImportRecords As ImmutableArray(Of ImportRecord) = importRecordGroups(1)
Assert.Empty(fileLevelImportRecords)
AssertEx.All(projectLevelImportRecords, Function(record) record.TargetAssemblyAlias Is Nothing)
AssertEx.All(projectLevelImportRecords, Function(record) record.TargetKind = ImportTargetKind.Namespace)
AssertEx.All(projectLevelImportRecords, Function(record) record.Alias Is Nothing)
AssertEx.SetEqual(projectLevelImportRecords.Select(Function(record) record.TargetString), namespaceNames)
End Sub
End Class
End Namespace
|