/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EvaluationContext.vb
644 строки
33 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 System.Collections.Immutable Imports System.Collections.ObjectModel Imports System.IO Imports System.Reflection Imports System.Reflection.Metadata Imports System.Reflection.Metadata.Ecma335 Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.CodeGen Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.Debugging Imports Microsoft.CodeAnalysis.Emit Imports Microsoft.CodeAnalysis.ExpressionEvaluator Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.DiaSymReader Imports Microsoft.VisualStudio.Debugger.Evaluation Imports Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation Imports Roslyn.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator Friend NotInheritable Class EvaluationContext Inherits EvaluationContextBase ' These names are arbitrary, so we'll just use the same names as ' the C# expression compiler. Private Const s_typeName = "<>x" Private Const s_methodName = "<>m0" Friend ReadOnly MethodContextReuseConstraints As MethodContextReuseConstraints? Friend ReadOnly Compilation As VisualBasicCompilation Private ReadOnly _currentFrame As MethodSymbol Private ReadOnly _currentSourceMethod As MethodSymbol Private ReadOnly _locals As ImmutableArray(Of LocalSymbol) Private ReadOnly _inScopeHoistedLocalSlots As ImmutableSortedSet(Of Integer) Private ReadOnly _methodDebugInfo As MethodDebugInfo(Of TypeSymbol, LocalSymbol) Private Sub New( methodContextReuseConstraints As MethodContextReuseConstraints?, compilation As VisualBasicCompilation, currentFrame As MethodSymbol, currentSourceMethod As MethodSymbol, locals As ImmutableArray(Of LocalSymbol), inScopeHoistedLocalSlots As ImmutableSortedSet(Of Integer), methodDebugInfo As MethodDebugInfo(Of TypeSymbol, LocalSymbol)) Me.MethodContextReuseConstraints = methodContextReuseConstraints Me.Compilation = compilation _currentFrame = currentFrame _currentSourceMethod = currentSourceMethod _locals = locals _inScopeHoistedLocalSlots = inScopeHoistedLocalSlots _methodDebugInfo = methodDebugInfo End Sub ''' <summary> ''' Create a context for evaluating expressions at a type scope. ''' </summary> ''' <param name="compilation">Compilation.</param> ''' <param name="moduleId">Module containing type.</param> ''' <param name="typeToken">Type metadata token.</param> ''' <returns>Evaluation context.</returns> ''' <remarks> ''' No locals since locals are associated with methods, not types. ''' </remarks> Friend Shared Function CreateTypeContext( compilation As VisualBasicCompilation, moduleId As ModuleId, typeToken As Integer) As EvaluationContext Debug.Assert(MetadataTokens.Handle(typeToken).Kind = HandleKind.TypeDefinition) Dim currentType = compilation.GetType(moduleId, typeToken) Debug.Assert(currentType IsNot Nothing) Dim currentFrame = New SynthesizedContextMethodSymbol(currentType) Return New EvaluationContext( Nothing, compilation, currentFrame, Nothing, locals:=Nothing, inScopeHoistedLocalSlots:=Nothing, methodDebugInfo:=MethodDebugInfo(Of TypeSymbol, LocalSymbol).None) End Function ''' <summary> ''' Create a context for evaluating expressions within a method scope. ''' </summary> ''' <param name="previous">Previous context, if any, for possible re-use.</param> ''' <param name="metadataBlocks">Module metadata.</param> ''' <param name="symReader"><see cref="ISymUnmanagedReader"/> for PDB associated with <paramref name="moduleId"/>.</param> ''' <param name="moduleId">Module containing method.</param> ''' <param name="methodToken">Method metadata token.</param> ''' <param name="methodVersion">Method version.</param> ''' <param name="ilOffset">IL offset of instruction pointer in method.</param> ''' <param name="localSignatureToken">Method local signature token.</param> ''' <returns>Evaluation context.</returns> Friend Shared Function CreateMethodContext( previous As VisualBasicMetadataContext, metadataBlocks As ImmutableArray(Of MetadataBlock), lazyAssemblyReaders As Lazy(Of ImmutableArray(Of AssemblyReaders)), symReader As Object, moduleId As ModuleId, methodToken As Integer, methodVersion As Integer, ilOffset As UInteger, localSignatureToken As Integer) As EvaluationContext Dim offset = NormalizeILOffset(ilOffset) Dim compilation As VisualBasicCompilation = metadataBlocks.ToCompilation(Nothing, MakeAssemblyReferencesKind.AllAssemblies) Return CreateMethodContext( compilation, lazyAssemblyReaders, symReader, moduleId, methodToken, methodVersion, offset, localSignatureToken) End Function ''' <summary> ''' Create a context for evaluating expressions within a method scope. ''' </summary> ''' <param name="compilation">Compilation.</param> ''' <param name="symReader"><see cref="ISymUnmanagedReader"/> for PDB associated with <paramref name="moduleId"/>.</param> ''' <param name="moduleId">Module containing method.</param> ''' <param name="methodToken">Method metadata token.</param> ''' <param name="methodVersion">Method version.</param> ''' <param name="ilOffset">IL offset of instruction pointer in method.</param> ''' <param name="localSignatureToken">Method local signature token.</param> ''' <returns>Evaluation context.</returns> Friend Shared Function CreateMethodContext( compilation As VisualBasicCompilation, lazyAssemblyReaders As Lazy(Of ImmutableArray(Of AssemblyReaders)), symReader As Object, moduleId As ModuleId, methodToken As Integer, methodVersion As Integer, ilOffset As Integer, localSignatureToken As Integer) As EvaluationContext Dim methodHandle = CType(MetadataTokens.Handle(methodToken), MethodDefinitionHandle) Dim currentSourceMethod = compilation.GetSourceMethod(moduleId, methodHandle) Dim localSignatureHandle = If(localSignatureToken <> 0, CType(MetadataTokens.Handle(localSignatureToken), StandaloneSignatureHandle), Nothing) Dim currentFrame = compilation.GetMethod(moduleId, methodHandle) Debug.Assert(currentFrame IsNot Nothing) Dim symbolProvider = New VisualBasicEESymbolProvider(DirectCast(currentFrame.ContainingModule, PEModuleSymbol), currentFrame) Dim metadataDecoder = New MetadataDecoder(DirectCast(currentFrame.ContainingModule, PEModuleSymbol), currentFrame) Dim localInfo = metadataDecoder.GetLocalInfo(localSignatureHandle) Dim debugInfo As MethodDebugInfo(Of TypeSymbol, LocalSymbol) If IsDteeEntryPoint(currentFrame) Then debugInfo = SynthesizeMethodDebugInfoForDtee(lazyAssemblyReaders.Value) Else Dim typedSymReader = DirectCast(symReader, ISymUnmanagedReader3) debugInfo = MethodDebugInfo(Of TypeSymbol, LocalSymbol).ReadMethodDebugInfo(typedSymReader, symbolProvider, methodToken, methodVersion, ilOffset, isVisualBasicMethod:=True) End If Dim reuseSpan = debugInfo.ReuseSpan Dim inScopeHoistedLocalSlots As ImmutableSortedSet(Of Integer) If debugInfo.HoistedLocalScopeRecords.IsDefault Then inScopeHoistedLocalSlots = GetInScopeHoistedLocalSlots(debugInfo.LocalVariableNames) Else inScopeHoistedLocalSlots = debugInfo.GetInScopeHoistedLocalIndices(ilOffset, reuseSpan) End If Dim localNames = debugInfo.LocalVariableNames.WhereAsArray( Function(name) name Is Nothing OrElse Not name.StartsWith(GeneratedNameConstants.StateMachineHoistedUserVariableOrDisplayClassPrefix, StringComparison.Ordinal)) Dim localsBuilder = ArrayBuilder(Of LocalSymbol).GetInstance() MethodDebugInfo(Of TypeSymbol, LocalSymbol).GetLocals(localsBuilder, symbolProvider, localNames, localInfo, Nothing, debugInfo.TupleLocalMap) GetStaticLocals(localsBuilder, currentFrame, methodHandle, metadataDecoder) localsBuilder.AddRange(debugInfo.LocalConstants) Return New EvaluationContext( New MethodContextReuseConstraints(moduleId, methodToken, methodVersion, reuseSpan), compilation, currentFrame, currentSourceMethod, localsBuilder.ToImmutableAndFree(), inScopeHoistedLocalSlots, debugInfo) End Function Private Shared Function GetInScopeHoistedLocalSlots(allLocalNames As ImmutableArray(Of String)) As ImmutableSortedSet(Of Integer) Dim builder = ArrayBuilder(Of Integer).GetInstance() For Each localName In allLocalNames Dim hoistedLocalName As String = Nothing Dim hoistedLocalSlot As Integer = 0 If localName IsNot Nothing AndAlso GeneratedNameParser.TryParseStateMachineHoistedUserVariableOrDisplayClassName(localName, hoistedLocalName, hoistedLocalSlot) Then builder.Add(hoistedLocalSlot) End If Next Dim result = builder.ToImmutableSortedSet() builder.Free() Return result End Function ''' <summary> ''' When using DTEE with the hosting process enabled, if the assembly being debugged doesn't have ''' a Main method, the debugger will actually stop in a driver method in the hosting process. ''' As in the native EE, we detect such methods by name (respecting case). ''' </summary> ''' <remarks> ''' Logic copied from ProcedureContext::IsDteeEntryPoint. ''' Friend for testing. ''' </remarks> ''' <seealso cref="SynthesizeMethodDebugInfoForDtee"/> Friend Shared Function IsDteeEntryPoint(currentFrame As MethodSymbol) As Boolean Dim typeName = currentFrame.ContainingType.Name Dim methodName = currentFrame.Name Return _ (String.Equals(typeName, "HostProc", StringComparison.Ordinal) AndAlso ' DLL String.Equals(methodName, "BreakForDebugger", StringComparison.Ordinal)) OrElse (String.Equals(typeName, "AppDomain", StringComparison.Ordinal) AndAlso ' WPF app String.Equals(methodName, "ExecuteAssembly", StringComparison.Ordinal)) End Function ''' <summary> ''' When using DTEE with the hosting process enabled, if the assembly being debugged doesn't have ''' a Main method, the debugger will actually stop in a driver method in the hosting process. ''' (This condition is detected by <see cref="IsDteeEntryPoint"/>.) ''' ''' Since such driver methods have no knowledge of the assembly being debugged, we synthesize ''' imports to bring symbols from the target assembly into scope (for convenience). In particular, ''' we import the root namespace of any assembly that isn't obviously a framework assembly and ''' any namespace containing a module type. ''' </summary> ''' <remarks> ''' Logic copied from ProcedureContext::LoadImportsAndDefaultNamespaceForDteeEntryPoint. ''' Friend for testing. ''' </remarks> ''' <seealso cref="IsDteeEntryPoint"/> ''' <seealso cref="PENamedTypeSymbol.TypeKind"/> Friend Shared Function SynthesizeMethodDebugInfoForDtee(assemblyReaders As ImmutableArray(Of AssemblyReaders)) As MethodDebugInfo(Of TypeSymbol, LocalSymbol) Dim [imports] = PooledHashSet(Of String).GetInstance() For Each readers In assemblyReaders Dim metadataReader = readers.MetadataReader Dim symReader = DirectCast(readers.SymReader, ISymUnmanagedReader3) ' Ignore assemblies for which we don't have PDBs. If symReader Is Nothing Then Continue For Try For Each typeDefHandle In metadataReader.TypeDefinitions Dim typeDef = metadataReader.GetTypeDefinition(typeDefHandle) Dim foundAttributeType = False ' VB does ignores the StandardModuleAttribute on interfaces and nested ' or generic types (see PENamedTypeSymbol.TypeKind). If Not PEModule.IsNested(typeDef.Attributes) AndAlso typeDef.GetGenericParameters().Count = 0 AndAlso (typeDef.Attributes And TypeAttributes.[Interface]) = 0 AndAlso PEModule.FindTargetAttribute(metadataReader, typeDefHandle, AttributeDescription.StandardModuleAttribute, foundAttributeType).HasValue Then Dim namespaceName = metadataReader.GetString(typeDef.Namespace) [imports].Add(namespaceName) End If Next For Each methodDefHandle In metadataReader.MethodDefinitions ' TODO: this can be done better ' EnC can't change the default namespace of the assembly, so version 1 will suffice. Dim debugInfo = MethodDebugInfo(Of TypeSymbol, LocalSymbol).ReadMethodDebugInfo(symReader, Nothing, metadataReader.GetToken(methodDefHandle), methodVersion:=1, ilOffset:=0, isVisualBasicMethod:=True) ' Some methods aren't decorated with import custom debug info. If Not String.IsNullOrEmpty(debugInfo.DefaultNamespaceName) Then ' NOTE: We're adding it as a project-level import, not as the default namespace ' (because there's one for each assembly and they can't all be the default). [imports].Add(debugInfo.DefaultNamespaceName) ' The default namespace should be the same for all methods, so we only need to check one. Exit For End If Next Catch ex As BadImageFormatException ' This will only prevent us from synthesizing imports for the module types in ' one assembly - it is decidedly recoverable. End Try Next Dim projectLevelImportRecords = ImmutableArray.CreateRange([imports].Select( Function(namespaceName) New ImportRecord(ImportTargetKind.Namespace, alias:=Nothing, targetType:=Nothing, targetString:=namespaceName, targetAssembly:=Nothing, targetAssemblyAlias:=Nothing))) [imports].Free() Dim fileLevelImportRecords = ImmutableArray(Of ImportRecord).Empty Dim importRecordGroups = ImmutableArray.Create(fileLevelImportRecords, projectLevelImportRecords) Return New MethodDebugInfo(Of TypeSymbol, LocalSymbol)( hoistedLocalScopeRecords:=ImmutableArray(Of HoistedLocalScopeRecord).Empty, importRecordGroups:=importRecordGroups, defaultNamespaceName:="", externAliasRecords:=ImmutableArray(Of ExternAliasRecord).Empty, dynamicLocalMap:=Nothing, tupleLocalMap:=Nothing, localVariableNames:=ImmutableArray(Of String).Empty, localConstants:=ImmutableArray(Of LocalSymbol).Empty, reuseSpan:=Nothing, containingDocumentName:=Nothing, isPrimaryConstructor:=False) End Function Friend Function CreateCompilationContext(withSyntax As Boolean) As CompilationContext Return New CompilationContext( Compilation, _currentFrame, _currentSourceMethod, _locals, _inScopeHoistedLocalSlots, _methodDebugInfo, withSyntax) End Function Friend Overrides Function CompileExpression( expr As String, compilationFlags As DkmEvaluationFlags, aliases As ImmutableArray(Of [Alias]), diagnostics As DiagnosticBag, <Out> ByRef resultProperties As ResultProperties, testData As Microsoft.CodeAnalysis.CodeGen.CompilationTestData) As CompileResult resultProperties = Nothing Dim formatSpecifiers As ReadOnlyCollection(Of String) = Nothing Dim syntax = If((compilationFlags And DkmEvaluationFlags.TreatAsExpression) <> 0, expr.ParseExpression(diagnostics, allowFormatSpecifiers:=True, formatSpecifiers:=formatSpecifiers), expr.ParseStatement(diagnostics)) If syntax Is Nothing Then Return Nothing End If If Not IsSupportedDebuggerStatement(syntax) Then diagnostics.Add(New SimpleMessageDiagnostic(String.Format(Resources.InvalidDebuggerStatement, syntax.Kind))) Return Nothing End If Dim context = Me.CreateCompilationContext(withSyntax:=True) Dim synthesizedMethod As EEMethodSymbol = Nothing Dim moduleBuilder = context.Compile(DirectCast(syntax, ExecutableStatementSyntax), s_typeName, s_methodName, aliases, testData, diagnostics, synthesizedMethod) If moduleBuilder Is Nothing Then Return Nothing End If Using stream As New MemoryStream() Cci.PeWriter.WritePeToStream( New EmitContext(moduleBuilder, Nothing, diagnostics, metadataOnly:=False, includePrivateMembers:=True), context.MessageProvider, Function() stream, getPortablePdbStreamOpt:=Nothing, nativePdbWriterOpt:=Nothing, pdbPathOpt:=Nothing, metadataOnly:=False, isDeterministic:=False, emitTestCoverageData:=False, privateKeyOpt:=Nothing, cancellationToken:=Nothing) If diagnostics.HasAnyErrors() Then Return Nothing End If Debug.Assert(synthesizedMethod.ContainingType.MetadataName = s_typeName) Debug.Assert(synthesizedMethod.MetadataName = s_methodName) resultProperties = synthesizedMethod.ResultProperties Return New VisualBasicCompileResult( stream.ToArray(), synthesizedMethod, formatSpecifiers) End Using End Function Friend Overrides Function CompileAssignment( target As String, expr As String, aliases As ImmutableArray(Of [Alias]), diagnostics As DiagnosticBag, <Out> ByRef resultProperties As ResultProperties, testData As Microsoft.CodeAnalysis.CodeGen.CompilationTestData) As CompileResult Dim assignment = target.ParseAssignment(expr, diagnostics) If assignment Is Nothing Then Return Nothing End If Dim context = Me.CreateCompilationContext(withSyntax:=True) Dim synthesizedMethod As EEMethodSymbol = Nothing Dim modulebuilder = context.Compile(assignment, s_typeName, s_methodName, aliases, testData, diagnostics, synthesizedMethod) If modulebuilder Is Nothing Then Return Nothing End If Using stream As New MemoryStream() Cci.PeWriter.WritePeToStream( New EmitContext(modulebuilder, Nothing, diagnostics, metadataOnly:=False, includePrivateMembers:=True), context.MessageProvider, Function() stream, getPortablePdbStreamOpt:=Nothing, nativePdbWriterOpt:=Nothing, pdbPathOpt:=Nothing, metadataOnly:=False, isDeterministic:=False, emitTestCoverageData:=False, privateKeyOpt:=Nothing, cancellationToken:=Nothing) If diagnostics.HasAnyErrors() Then Return Nothing End If Debug.Assert(synthesizedMethod.ContainingType.MetadataName = s_typeName) Debug.Assert(synthesizedMethod.MetadataName = s_methodName) Dim properties = synthesizedMethod.ResultProperties resultProperties = New ResultProperties( properties.Flags Or DkmClrCompilationResultFlags.PotentialSideEffect, properties.Category, properties.AccessType, properties.StorageType, properties.ModifierFlags) Return New VisualBasicCompileResult( stream.ToArray(), synthesizedMethod, formatSpecifiers:=Nothing) End Using End Function Private Shared ReadOnly s_emptyBytes As New ReadOnlyCollection(Of Byte)(Array.Empty(Of Byte)) Friend Overrides Function CompileGetLocals( locals As ArrayBuilder(Of LocalAndMethod), argumentsOnly As Boolean, aliases As ImmutableArray(Of [Alias]), diagnostics As DiagnosticBag, <Out> ByRef typeName As String, testData As CompilationTestData) As ReadOnlyCollection(Of Byte) Dim context = Me.CreateCompilationContext(withSyntax:=False) Dim modulebuilder = context.CompileGetLocals(s_typeName, locals, argumentsOnly, aliases, testData, diagnostics) Dim assembly As ReadOnlyCollection(Of Byte) = Nothing If modulebuilder IsNot Nothing AndAlso locals.Count > 0 Then Using stream As New MemoryStream() Cci.PeWriter.WritePeToStream( New EmitContext(modulebuilder, Nothing, diagnostics, metadataOnly:=False, includePrivateMembers:=True), context.MessageProvider, Function() stream, getPortablePdbStreamOpt:=Nothing, nativePdbWriterOpt:=Nothing, pdbPathOpt:=Nothing, metadataOnly:=False, isDeterministic:=False, emitTestCoverageData:=False, privateKeyOpt:=Nothing, cancellationToken:=Nothing) If Not diagnostics.HasAnyErrors() Then assembly = New ReadOnlyCollection(Of Byte)(stream.ToArray()) End If End Using End If If assembly Is Nothing Then locals.Clear() assembly = s_emptyBytes End If typeName = EvaluationContext.s_typeName Return assembly End Function ''' <summary> ''' Include static locals for the given method. Static locals ''' are represented as fields on the containing class named ''' "$STATIC$[methodname]$[methodsignature]$[localname]". ''' </summary> Private Shared Sub GetStaticLocals( builder As ArrayBuilder(Of LocalSymbol), method As MethodSymbol, methodHandle As MethodDefinitionHandle, metadataDecoder As MetadataDecoder) Dim type = method.ContainingType If type.TypeKind <> TypeKind.Class Then Return End If For Each member In type.GetMembers() If member.Kind <> SymbolKind.Field Then Continue For End If Dim methodName As String = Nothing Dim methodSignature As String = Nothing Dim localName As String = Nothing If GeneratedNameParser.TryParseStaticLocalFieldName(member.Name, methodName, methodSignature, localName) AndAlso String.Equals(methodName, method.Name, StringComparison.Ordinal) AndAlso String.Equals(methodSignature, GetMethodSignatureString(metadataDecoder, methodHandle), StringComparison.Ordinal) Then builder.Add(New EEStaticLocalSymbol(method, DirectCast(member, FieldSymbol), localName)) End If Next End Sub Private Shared Function GetMethodSignatureString(metadataDecoder As MetadataDecoder, methodHandle As MethodDefinitionHandle) As String Dim [module] = metadataDecoder.Module Dim signatureHandle = [module].GetMethodSignatureOrThrow(methodHandle) Dim signatureReader = [module].GetMemoryReaderOrThrow(signatureHandle) Dim signature = signatureReader.ReadBytes(signatureReader.Length) Return GeneratedNames.MakeSignatureString(signature) End Function Friend Overrides Function HasDuplicateTypesOrAssemblies(diagnostic As Diagnostic) As Boolean Select Case CType(diagnostic.Code, ERRID) Case ERRID.ERR_DuplicateReference2, ERRID.ERR_DuplicateReferenceStrong, ERRID.ERR_AmbiguousInUnnamedNamespace1, ERRID.ERR_AmbiguousInNamespace2, ERRID.ERR_NoMostSpecificOverload2, ERRID.ERR_AmbiguousInModules2 Return True Case Else Return False End Select End Function Friend Overrides Function GetMissingAssemblyIdentities(diagnostic As Diagnostic, linqLibrary As AssemblyIdentity) As ImmutableArray(Of AssemblyIdentity) Return GetMissingAssemblyIdentitiesHelper(CType(diagnostic.Code, ERRID), diagnostic.Arguments, Me.Compilation.GlobalNamespace, linqLibrary) End Function ''' <remarks> ''' Friend for testing. ''' </remarks> Friend Shared Function GetMissingAssemblyIdentitiesHelper(code As ERRID, arguments As IReadOnlyList(Of Object), globalNamespace As NamespaceSymbol, linqLibrary As AssemblyIdentity) As ImmutableArray(Of AssemblyIdentity) Debug.Assert(linqLibrary IsNot Nothing) Select Case code Case ERRID.ERR_UnreferencedAssemblyEvent3, ERRID.ERR_UnreferencedAssembly3 For Each argument As Object In arguments Dim identity = If(TryCast(argument, AssemblyIdentity), TryCast(argument, AssemblySymbol)?.Identity) If IsValidMissingAssemblyIdentity(identity) Then Return ImmutableArray.Create(identity) End If Next Case ERRID.ERR_ForwardedTypeUnavailable3 If arguments.Count = 3 Then Dim identity As AssemblyIdentity = TryCast(arguments(2), AssemblySymbol)?.Identity If IsValidMissingAssemblyIdentity(identity) Then Return ImmutableArray.Create(identity) End If End If Case ERRID.ERR_NameNotMember2 If arguments.Count = 2 Then Dim namespaceName = TryCast(arguments(0), String) Dim containingNamespace = TryCast(arguments(1), NamespaceSymbol) If namespaceName IsNot Nothing AndAlso containingNamespace IsNot Nothing AndAlso HasConstituentFromWindowsAssembly(containingNamespace) Then ' This is just a heuristic, but it has the advantage of being portable, particularly ' across different versions of (desktop) windows. Dim identity = New AssemblyIdentity($"{containingNamespace.ToDisplayString}.{namespaceName}", contentType:=AssemblyContentType.WindowsRuntime) Return ImmutableArray.Create(identity) Else ' Maybe it's a missing LINQ extension method. Let's try adding the "LINQ library" to see if that helps. Return ImmutableArray.Create(linqLibrary) End If End If Case ERRID.ERR_UndefinedType1 If arguments.Count = 1 Then Dim qualifiedName = TryCast(arguments(0), String) If Not String.IsNullOrEmpty(qualifiedName) Then Dim nameParts = qualifiedName.Split("."c) Dim numParts = nameParts.Length Dim pos = 0 If CaseInsensitiveComparison.Comparer.Equals(nameParts(0), "global") Then pos = 1 Debug.Assert(pos < numParts) End If Dim currNamespace = globalNamespace While pos < numParts Dim nextNamespace = currNamespace.GetMembers(nameParts(pos)).OfType(Of NamespaceSymbol).SingleOrDefault() If nextNamespace Is Nothing Then Exit While End If pos += 1 currNamespace = nextNamespace End While If currNamespace IsNot globalNamespace AndAlso HasConstituentFromWindowsAssembly(currNamespace) AndAlso pos < numParts Then Dim nextNamePart = nameParts(pos) If nextNamePart.All(AddressOf SyntaxFacts.IsIdentifierPartCharacter) Then ' This is just a heuristic, but it has the advantage of being portable, particularly ' across different versions of (desktop) windows. Dim identity = New AssemblyIdentity($"{currNamespace.ToDisplayString}.{nameParts(pos)}", contentType:=AssemblyContentType.WindowsRuntime) Return ImmutableArray.Create(identity) End If End If End If End If Case ERRID.ERR_XmlFeaturesNotAvailable Return ImmutableArray.Create(SystemIdentity, linqLibrary, SystemXmlIdentity, SystemXmlLinqIdentity) Case ERRID.ERR_MissingRuntimeHelper Return ImmutableArray.Create(MicrosoftVisualBasicIdentity) End Select Return Nothing End Function Private Shared Function HasConstituentFromWindowsAssembly(namespaceSymbol As NamespaceSymbol) As Boolean Return namespaceSymbol.ConstituentNamespaces.Any(Function(n) n.ContainingAssembly.Identity.IsWindowsAssemblyIdentity) End Function Private Shared Function IsValidMissingAssemblyIdentity(identity As AssemblyIdentity) As Boolean Return identity IsNot Nothing AndAlso Not identity.Equals(MissingCorLibrarySymbol.Instance.Identity) End Function End Class End Namespace