/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Symbols/Source/SourceModuleSymbol.vb
1 216 строк
60 KB
Tomáš Matoušek
Refactoring of extension methods in source packages (#78620) - take 2 (#78894)
26 июн 2025, 18:42
Не верифицирован
26 июн 2025, 18:42
05fc006
Код
Авторство
О чём код?
' 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.Concurrent Imports System.Collections.Immutable Imports System.Runtime.CompilerServices Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.ErrorReporting Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' <summary> ''' Represents the primary module of an assembly being built by compiler. ''' </summary> ''' <remarks></remarks> Partial Friend NotInheritable Class SourceModuleSymbol Inherits NonMissingModuleSymbol Implements IAttributeTargetSymbol ''' <summary> ''' Owning assembly. ''' </summary> ''' <remarks></remarks> Private ReadOnly _assemblySymbol As SourceAssemblySymbol ' The declaration table for all the source files. Private ReadOnly _declarationTable As DeclarationTable ' Options that control compilation Private ReadOnly _options As VisualBasicCompilationOptions ' Module attributes Private _lazyCustomAttributesBag As CustomAttributesBag(Of VisualBasicAttributeData) Private _lazyContainsExtensionMethods As Byte = ThreeState.Unknown Private _lazyAssembliesToEmbedTypesFrom As ImmutableArray(Of AssemblySymbol) Private _lazyContainsExplicitDefinitionOfNoPiaLocalTypes As ThreeState = ThreeState.Unknown Private _locations As ImmutableArray(Of Location) ''' <summary> ''' Holds diagnostics not related to source code ''' in any particular source file ''' </summary> Private ReadOnly _diagnosticBagDeclare As New DiagnosticBag() Private _hasBadAttributes As Boolean Friend ReadOnly Property Options As VisualBasicCompilationOptions Get Return _options End Get End Property ' A concurrent dictionary that hold SourceFile objects for each source file, created ' on demand. Each source file object holds information about the source that is specific to a particular ' compilation and doesn't survive edits in any way (unlike the declaration table, which is incrementally ' updated between compilations as edits occur.) Private ReadOnly _sourceFileMap As New ConcurrentDictionary(Of SyntaxTree, SourceFile) ' lazily populated with the global namespace symbol Private _lazyGlobalNamespace As SourceNamespaceSymbol ' lazily populated with the bound imports Private _lazyBoundImports As BoundImports Private _lazyBoundImportsAdditionalDiagnostics As StrongBox(Of ReadOnlyBindingDiagnostic(Of AssemblySymbol)) ' lazily populate with quick attribute checker that is initialized with the imports. Private _lazyQuickAttributeChecker As QuickAttributeChecker ' lazily populate with diagnostics validating linked assemblies. Private _lazyLinkedAssemblyDiagnostics As ImmutableArray(Of Diagnostic) Private _lazyTypesWithDefaultInstanceAlias As Dictionary(Of NamedTypeSymbol, SynthesizedMyGroupCollectionPropertySymbol) Private Shared ReadOnly s_noTypesWithDefaultInstanceAlias As New Dictionary(Of NamedTypeSymbol, SynthesizedMyGroupCollectionPropertySymbol)() Friend Sub New(assemblySymbol As SourceAssemblySymbol, declarationTable As DeclarationTable, options As VisualBasicCompilationOptions, nameAndExtension As String) Debug.Assert(assemblySymbol IsNot Nothing) _assemblySymbol = assemblySymbol _declarationTable = declarationTable _options = options _nameAndExtension = nameAndExtension End Sub Friend Overrides ReadOnly Property Ordinal As Integer Get Return 0 End Get End Property Friend Overrides ReadOnly Property Machine As System.Reflection.PortableExecutable.Machine Get Select Case DeclaringCompilation.Options.Platform Case Platform.Arm64 Return System.Reflection.PortableExecutable.Machine.Arm64 Case Platform.Arm Return System.Reflection.PortableExecutable.Machine.ArmThumb2 Case Platform.X64 Return System.Reflection.PortableExecutable.Machine.Amd64 Case Platform.Itanium Return System.Reflection.PortableExecutable.Machine.IA64 Case Else Return System.Reflection.PortableExecutable.Machine.I386 End Select End Get End Property Friend Overrides ReadOnly Property Bit32Required As Boolean Get Return DeclaringCompilation.Options.Platform = Platform.X86 End Get End Property Public Overrides ReadOnly Property ContainingSymbol As Symbol Get Return _assemblySymbol End Get End Property Public Overrides ReadOnly Property ContainingAssembly As AssemblySymbol Get Return _assemblySymbol End Get End Property Public ReadOnly Property ContainingSourceAssembly As SourceAssemblySymbol Get Return _assemblySymbol End Get End Property ''' <summary> ''' This override is essential - it's a base case of the recursive definition. ''' </summary> Friend Overrides ReadOnly Property DeclaringCompilation As VisualBasicCompilation Get Return _assemblySymbol.DeclaringCompilation End Get End Property Private ReadOnly _nameAndExtension As String Public Overrides ReadOnly Property Name As String Get Return _nameAndExtension End Get End Property ''' <summary> ''' Get the SourceFile object associated with a root declaration. ''' Returns Nothing if the tree doesn't belong to the compilation. ''' </summary> Friend Function TryGetSourceFile(tree As SyntaxTree) As SourceFile Debug.Assert(tree IsNot Nothing) Dim srcFile As SourceFile = Nothing If _sourceFileMap.TryGetValue(tree, srcFile) Then Return srcFile ElseIf _assemblySymbol.DeclaringCompilation.AllSyntaxTrees.Contains(tree) Then srcFile = New SourceFile(Me, tree) Return _sourceFileMap.GetOrAdd(tree, srcFile) Else Return Nothing End If End Function ' Gets the global namespace for that merges the global namespace across all source files. Public Overrides ReadOnly Property GlobalNamespace As NamespaceSymbol Get If _lazyGlobalNamespace Is Nothing Then Dim globalNS = New SourceNamespaceSymbol(DeclaringCompilation.MergedRootDeclaration, Nothing, Me) Interlocked.CompareExchange(_lazyGlobalNamespace, globalNS, Nothing) End If Return _lazyGlobalNamespace End Get End Property ' Get the "root" or default namespace that all source types are declared inside. This may be the global namespace ' or may be another namespace. This is a non-merged, source only namespace. Friend ReadOnly Property RootNamespace As NamespaceSymbol Get Dim result = Me.GlobalNamespace.LookupNestedNamespace(Me.Options.GetRootNamespaceParts()) Debug.Assert(result IsNot Nothing, "Something is deeply wrong with the declaration table or the symbol table") Return result End Get End Property Public Overrides ReadOnly Property Locations As ImmutableArray(Of Location) Get If _locations.IsDefault Then ImmutableInterlocked.InterlockedInitialize( _locations, DeclaringCompilation.MergedRootDeclaration.Declarations.SelectAsArray(Function(d) d.Location)) End If Return _locations End Get End Property Friend ReadOnly Property SyntaxTrees As IEnumerable(Of SyntaxTree) Get Return _assemblySymbol.DeclaringCompilation.AllSyntaxTrees End Get End Property Public ReadOnly Property DefaultAttributeLocation As AttributeLocation Implements IAttributeTargetSymbol.DefaultAttributeLocation Get Return AttributeLocation.Module End Get End Property ''' <summary> ''' Gets the attributes applied on this symbol. ''' Returns an empty array if there are no attributes. ''' </summary> ''' <remarks> ''' NOTE: This method should always be kept as a NotOverridable method. ''' If you want to override attribute binding logic for a sub-class, then override <see cref="GetAttributesBag"/> method. ''' </remarks> Public Overrides Function GetAttributes() As ImmutableArray(Of VisualBasicAttributeData) Return Me.GetAttributesBag().Attributes End Function Private Function GetAttributesBag() As CustomAttributesBag(Of VisualBasicAttributeData) If _lazyCustomAttributesBag Is Nothing OrElse Not _lazyCustomAttributesBag.IsSealed Then Dim mergedAttributes = DirectCast(Me.ContainingAssembly, SourceAssemblySymbol).GetAttributeDeclarations() LoadAndValidateAttributes(OneOrMany.Create(mergedAttributes), _lazyCustomAttributesBag) End If Return _lazyCustomAttributesBag End Function Friend Function GetDecodedWellKnownAttributeData() As CommonModuleWellKnownAttributeData Dim attributesBag As CustomAttributesBag(Of VisualBasicAttributeData) = Me._lazyCustomAttributesBag If attributesBag Is Nothing OrElse Not attributesBag.IsDecodedWellKnownAttributeDataComputed Then attributesBag = Me.GetAttributesBag() End If Return DirectCast(attributesBag.DecodedWellKnownAttributeData, CommonModuleWellKnownAttributeData) End Function ' Get a quick attribute checker that can be used for quick attributes checks, initialized with project-level ' aliases. Public ReadOnly Property QuickAttributeChecker As QuickAttributeChecker Get If _lazyQuickAttributeChecker Is Nothing Then Interlocked.CompareExchange(_lazyQuickAttributeChecker, CreateQuickAttributeChecker(), Nothing) End If Return _lazyQuickAttributeChecker End Get End Property Friend ReadOnly Property AnyReferencedAssembliesAreLinked As Boolean Get Return GetAssembliesToEmbedTypesFrom().Length > 0 End Get End Property Friend Function MightContainNoPiaLocalTypes() As Boolean Return AnyReferencedAssembliesAreLinked OrElse ContainsExplicitDefinitionOfNoPiaLocalTypes End Function Friend Function GetAssembliesToEmbedTypesFrom() As ImmutableArray(Of AssemblySymbol) If _lazyAssembliesToEmbedTypesFrom.IsDefault Then AssertReferencesInitialized() Dim assemblies = ArrayBuilder(Of AssemblySymbol).GetInstance() For Each assembly In GetReferencedAssemblySymbols() If assembly.IsLinked Then assemblies.Add(assembly) End If Next ImmutableInterlocked.InterlockedInitialize(_lazyAssembliesToEmbedTypesFrom, assemblies.ToImmutableAndFree()) End If Debug.Assert(Not _lazyAssembliesToEmbedTypesFrom.IsDefault) Return _lazyAssembliesToEmbedTypesFrom End Function Friend ReadOnly Property ContainsExplicitDefinitionOfNoPiaLocalTypes As Boolean Get If _lazyContainsExplicitDefinitionOfNoPiaLocalTypes = ThreeState.Unknown Then _lazyContainsExplicitDefinitionOfNoPiaLocalTypes = NamespaceContainsExplicitDefinitionOfNoPiaLocalTypes(GlobalNamespace).ToThreeState() End If Debug.Assert(_lazyContainsExplicitDefinitionOfNoPiaLocalTypes <> ThreeState.Unknown) Return _lazyContainsExplicitDefinitionOfNoPiaLocalTypes = ThreeState.True End Get End Property Private Shared Function NamespaceContainsExplicitDefinitionOfNoPiaLocalTypes(ns As NamespaceSymbol) As Boolean For Each s In ns.GetMembersUnordered() Select Case s.Kind Case SymbolKind.Namespace If NamespaceContainsExplicitDefinitionOfNoPiaLocalTypes(DirectCast(s, NamespaceSymbol)) Then Return True End If Case SymbolKind.NamedType If DirectCast(s, NamedTypeSymbol).IsExplicitDefinitionOfNoPiaLocalType Then Return True End If End Select Next Return False End Function Private Function CreateQuickAttributeChecker() As QuickAttributeChecker ' First, initialize for the predefined attributes. Dim checker As New QuickAttributeChecker() checker.AddName(AttributeDescription.CaseInsensitiveExtensionAttribute.Name, QuickAttributes.Extension) checker.AddName(AttributeDescription.ObsoleteAttribute.Name, QuickAttributes.Obsolete) checker.AddName(AttributeDescription.DeprecatedAttribute.Name, QuickAttributes.Obsolete) checker.AddName(AttributeDescription.ExperimentalAttribute.Name, QuickAttributes.Obsolete) checker.AddName(AttributeDescription.MyGroupCollectionAttribute.Name, QuickAttributes.MyGroupCollection) checker.AddName(AttributeDescription.TypeIdentifierAttribute.Name, QuickAttributes.TypeIdentifier) ' Now process alias imports For Each globalImport In Options.GlobalImports If globalImport.Clause.Kind = SyntaxKind.SimpleImportsClause Then Dim simpleImportsClause = DirectCast(globalImport.Clause, SimpleImportsClauseSyntax) If simpleImportsClause.Alias IsNot Nothing Then checker.AddAlias(simpleImportsClause) End If End If Next checker.Seal() Return checker End Function ' Make sure the project level imports are bound. Private Sub EnsureImportsAreBound(cancellationToken As CancellationToken) If _lazyBoundImports Is Nothing Then If Interlocked.CompareExchange(_lazyBoundImports, BindImports(cancellationToken), Nothing) Is Nothing Then EnsureImportsAreValidated() End If End If End Sub Private Sub EnsureImportsAreValidated() If _lazyBoundImportsAdditionalDiagnostics Is Nothing Then Dim diagnosticBag = BindingDiagnosticBag.GetInstance() ValidateImports(_lazyBoundImports.MemberImports, _lazyBoundImports.MemberImportsInfo, _lazyBoundImports.AliasImports, _lazyBoundImports.AliasImportsInfo, diagnosticBag) Interlocked.CompareExchange(_lazyBoundImportsAdditionalDiagnostics, New StrongBox(Of ReadOnlyBindingDiagnostic(Of AssemblySymbol))(diagnosticBag.ToReadOnlyAndFree()), Nothing) End If End Sub ' Bind the project level imports. Private Function BindImports(cancellationToken As CancellationToken) As BoundImports Dim diagBag = BindingDiagnosticBag.GetInstance() Dim membersMap = New HashSet(Of NamespaceOrTypeSymbol) Dim aliasesMap = New Dictionary(Of String, AliasAndImportsClausePosition)(IdentifierComparison.Comparer) Dim membersBuilder = ArrayBuilder(Of NamespaceOrTypeAndImportsClausePosition).GetInstance() Dim membersInfoBuilder = ArrayBuilder(Of GlobalImportInfo).GetInstance() Dim aliasesBuilder = ArrayBuilder(Of AliasAndImportsClausePosition).GetInstance() Dim aliasesInfoBuilder = ArrayBuilder(Of GlobalImportInfo).GetInstance() Dim xmlNamespaces = New Dictionary(Of String, XmlNamespaceAndImportsClausePosition) Dim diagBagForThisImport = BindingDiagnosticBag.GetInstance() Try For Each globalImport In Options.GlobalImports cancellationToken.ThrowIfCancellationRequested() diagBagForThisImport.Clear() Dim data = New ModuleImportData(globalImport, membersMap, aliasesMap, membersBuilder, membersInfoBuilder, aliasesBuilder, aliasesInfoBuilder, xmlNamespaces, diagBagForThisImport.DependenciesBag) Dim binder As Binder = BinderBuilder.CreateBinderForProjectImports(Me, VisualBasicSyntaxTree.Dummy) binder.BindImportClause(globalImport.Clause, data, diagBagForThisImport.DiagnosticBag) ' Map diagnostics to new ones. ' Note, it is safe to resolve diagnostics here because we suppress obsolete diagnostics ' in ProjectImportsBinder. For Each d As Diagnostic In diagBagForThisImport.DiagnosticBag.AsEnumerable() ' NOTE: Dev10 doesn't report 'ERR_DuplicateImport1' for project level imports. If d.Code <> ERRID.ERR_DuplicateImport1 Then diagBag.Add(globalImport.MapDiagnostic(d)) End If Next diagBag.AddDependencies(diagBagForThisImport) Next Return New BoundImports( membersBuilder.ToImmutable(), membersInfoBuilder.ToImmutable(), aliasesMap, aliasesBuilder.ToImmutable(), aliasesInfoBuilder.ToImmutable(), If(xmlNamespaces.Count > 0, xmlNamespaces, Nothing), diagBag.ToReadOnly()) Finally membersBuilder.Free() membersInfoBuilder.Free() aliasesBuilder.Free() aliasesInfoBuilder.Free() diagBagForThisImport.Free() diagBag.Free() End Try End Function ''' <summary> ''' Data for Binder.BindImportClause that maintains flat lists of members, aliases, ''' and corresponding syntax references in addition to the dictionaries needed by ''' BindImportClause. The syntax references, instances of GlobalImportInfo, are used ''' later, when validating constraints, to generate Locations for constraint errors. ''' </summary> Private NotInheritable Class ModuleImportData Inherits ImportData Private ReadOnly _globalImport As GlobalImport Private ReadOnly _membersBuilder As ArrayBuilder(Of NamespaceOrTypeAndImportsClausePosition) Private ReadOnly _membersInfoBuilder As ArrayBuilder(Of GlobalImportInfo) Private ReadOnly _aliasesBuilder As ArrayBuilder(Of AliasAndImportsClausePosition) Private ReadOnly _aliasesInfoBuilder As ArrayBuilder(Of GlobalImportInfo) Private ReadOnly _dependencies As ICollection(Of AssemblySymbol) Public Sub New(globalImport As GlobalImport, membersMap As HashSet(Of NamespaceOrTypeSymbol), aliasesMap As Dictionary(Of String, AliasAndImportsClausePosition), membersBuilder As ArrayBuilder(Of NamespaceOrTypeAndImportsClausePosition), membersInfoBuilder As ArrayBuilder(Of GlobalImportInfo), aliasesBuilder As ArrayBuilder(Of AliasAndImportsClausePosition), aliasesInfoBuilder As ArrayBuilder(Of GlobalImportInfo), xmlNamespaces As Dictionary(Of String, XmlNamespaceAndImportsClausePosition), dependencies As ICollection(Of AssemblySymbol)) MyBase.New(membersMap, aliasesMap, xmlNamespaces) _globalImport = globalImport _membersBuilder = membersBuilder _membersInfoBuilder = membersInfoBuilder _aliasesBuilder = aliasesBuilder _aliasesInfoBuilder = aliasesInfoBuilder _dependencies = dependencies End Sub Public Overrides Sub AddMember( syntaxRef As SyntaxReference, member As NamespaceOrTypeSymbol, importsClausePosition As Integer, dependencies As IReadOnlyCollection(Of AssemblySymbol), isPrjectImportDeclaration As Boolean) ' Do not expose any locations for project level imports. This matches the effective logic ' we have for aliases, which are given NoLocation.Singleton (which never translates to a ' DeclaringSyntaxReference). Dim pair = New NamespaceOrTypeAndImportsClausePosition( member, importsClausePosition, If(isPrjectImportDeclaration, Nothing, syntaxRef), ImmutableArray(Of AssemblySymbol).Empty) Members.Add(member) _membersBuilder.Add(pair) _membersInfoBuilder.Add(New GlobalImportInfo(_globalImport, syntaxRef)) AddDependencies(dependencies) End Sub Private Sub AddDependencies(dependencies As IReadOnlyCollection(Of AssemblySymbol)) For Each dependency In dependencies _dependencies.Add(dependency) Next End Sub Public Overrides Sub AddAlias(syntaxRef As SyntaxReference, name As String, [alias] As AliasSymbol, importsClausePosition As Integer, dependencies As IReadOnlyCollection(Of AssemblySymbol)) Dim pair = New AliasAndImportsClausePosition([alias], importsClausePosition, syntaxRef, ImmutableArray(Of AssemblySymbol).Empty) Aliases.Add(name, pair) _aliasesBuilder.Add(pair) _aliasesInfoBuilder.Add(New GlobalImportInfo(_globalImport, syntaxRef)) AddDependencies(dependencies) End Sub End Class ''' <summary> ''' Perform any validation of import statements that must occur ''' after the import statements have been added to the module. ''' </summary> Private Sub ValidateImports( memberImports As ImmutableArray(Of NamespaceOrTypeAndImportsClausePosition), memberImportsInfo As ImmutableArray(Of GlobalImportInfo), aliasImports As ImmutableArray(Of AliasAndImportsClausePosition), aliasImportsInfo As ImmutableArray(Of GlobalImportInfo), diagnostics As BindingDiagnosticBag) ' TODO: Dev10 reports error on specific type parts rather than the import ' (reporting error on Object rather than C in C = A(Of Object) for instance). If Not memberImports.IsDefault Then For i = 0 To memberImports.Length - 1 Dim namespaceOrType As NamespaceOrTypeSymbol = memberImports(i).NamespaceOrType Dim type = TryCast(namespaceOrType, TypeSymbol) If type IsNot Nothing Then ValidateImport(type, memberImportsInfo(i), diagnostics) Else diagnostics.AddAssembliesUsedByNamespaceReference(DirectCast(namespaceOrType, NamespaceSymbol)) End If Next End If If Not aliasImports.IsDefault Then For i = 0 To aliasImports.Length - 1 Dim target As NamespaceOrTypeSymbol = aliasImports(i).Alias.Target Dim type = TryCast(target, TypeSymbol) If type IsNot Nothing Then ValidateImport(type, aliasImportsInfo(i), diagnostics) Else diagnostics.AddAssembliesUsedByNamespaceReference(DirectCast(target, NamespaceSymbol)) End If Next End If End Sub ''' <summary> ''' Perform validation of an import statement that must occur ''' after the statement has been added to the module. Specifically, ''' constraints are checked for generic type references. ''' </summary> Private Sub ValidateImport(type As TypeSymbol, info As GlobalImportInfo, diagnostics As BindingDiagnosticBag) Dim diagnosticsBuilder = ArrayBuilder(Of TypeParameterDiagnosticInfo).GetInstance() Dim useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo) = Nothing type.CheckAllConstraints( DeclaringCompilation.LanguageVersion, diagnosticsBuilder, useSiteDiagnosticsBuilder, template:=New CompoundUseSiteInfo(Of AssemblySymbol)(diagnostics, ContainingAssembly)) If useSiteDiagnosticsBuilder IsNot Nothing Then diagnosticsBuilder.AddRange(useSiteDiagnosticsBuilder) End If For Each pair In diagnosticsBuilder If pair.UseSiteInfo.DiagnosticInfo IsNot Nothing Then diagnostics.Add(info.Import.MapDiagnostic(New VBDiagnostic(pair.UseSiteInfo.DiagnosticInfo, info.SyntaxReference.GetLocation()))) End If diagnostics.AddDependencies(pair.UseSiteInfo) Next diagnosticsBuilder.Free() End Sub ' Get the project-level member imports, or Nothing if none. Friend ReadOnly Property MemberImports As ImmutableArray(Of NamespaceOrTypeAndImportsClausePosition) Get EnsureImportsAreBound(CancellationToken.None) Return _lazyBoundImports.MemberImports End Get End Property Friend ReadOnly Property AliasImports As ImmutableArray(Of AliasAndImportsClausePosition) Get EnsureImportsAreBound(CancellationToken.None) Return _lazyBoundImports.AliasImports End Get End Property ' Get the project level alias imports, or Nothing if none. Friend ReadOnly Property AliasImportsMap As Dictionary(Of String, AliasAndImportsClausePosition) Get EnsureImportsAreBound(CancellationToken.None) Return _lazyBoundImports.AliasImportsMap End Get End Property ' Get the project level xmlns imports, or Nothing if none. Friend ReadOnly Property XmlNamespaces As Dictionary(Of String, XmlNamespaceAndImportsClausePosition) Get EnsureImportsAreBound(CancellationToken.None) Return _lazyBoundImports.XmlNamespaces End Get End Property ''' <summary> ''' Get all the declaration errors in a single tree. ''' </summary> Friend Function GetDeclarationErrorsInTree(tree As SyntaxTree, filterSpanWithinTree As TextSpan?, locationFilter As Func(Of IEnumerable(Of Diagnostic), SyntaxTree, TextSpan?, IEnumerable(Of Diagnostic)), cancellationToken As CancellationToken) As ImmutableArray(Of Diagnostic) Dim builder = ArrayBuilder(Of Diagnostic).GetInstance() ' Force source file to generate errors for Imports and the like. Dim sourceFile As SourceFile = TryGetSourceFile(tree) Debug.Assert(sourceFile IsNot Nothing) If filterSpanWithinTree.HasValue Then Dim diagnostics = sourceFile.GetDeclarationErrorsInSpan(filterSpanWithinTree.Value, cancellationToken) diagnostics = locationFilter(diagnostics, tree, filterSpanWithinTree) builder.AddRange(diagnostics) Else sourceFile.GenerateAllDeclarationErrors() End If ' Force bind module and assembly attributes Me.GetAttributes() Me.ContainingAssembly.GetAttributes() ' Force all types to generate errors. Dim tasks As ConcurrentStack(Of Task) = If(ContainingSourceAssembly.DeclaringCompilation.Options.ConcurrentBuild, New ConcurrentStack(Of Task)(), Nothing) ' Force all types that were declared in this tree to generate errors. We may also generate declaration ' errors for other parts of partials; that's OK and those errors will be retained, but won't be in the ' diagnostic bag for this particular file. VisitAllSourceTypesAndNamespaces(Sub(typeOrNamespace As NamespaceOrTypeSymbol) If Not typeOrNamespace.IsDefinedInSourceTree(tree, filterSpanWithinTree) Then Return End If If typeOrNamespace.IsNamespace Then DirectCast(typeOrNamespace, SourceNamespaceSymbol).GenerateDeclarationErrorsInTree(tree, filterSpanWithinTree, cancellationToken) Else ' synthetic event delegates are not source types so use NamedTypeSymbol. Dim sourceType = DirectCast(typeOrNamespace, NamedTypeSymbol) sourceType.GenerateDeclarationErrors(cancellationToken) End If End Sub, tasks, cancellationToken) If tasks IsNot Nothing Then Dim curTask As Task = Nothing While tasks.TryPop(curTask) curTask.GetAwaiter().GetResult() End While End If ' Get all the errors that were generated. Dim declarationDiagnostics = sourceFile.DeclarationDiagnostics.AsEnumerable() ' Filter diagnostics outside the tree/span of interest. If locationFilter IsNot Nothing Then Debug.Assert(tree IsNot Nothing) declarationDiagnostics = locationFilter(declarationDiagnostics, tree, filterSpanWithinTree) End If For Each d As Diagnostic In declarationDiagnostics builder.Add(d) Next Return builder.ToImmutableAndFree() End Function ''' <summary> ''' Get all the declaration errors. ''' </summary> Friend Sub GetAllDeclarationErrors(diagnostics As BindingDiagnosticBag, cancellationToken As CancellationToken, ByRef hasExtensionMethods As Boolean) ' Bind project level imports EnsureImportsAreBound(cancellationToken) EnsureImportsAreValidated() ' Force all source files to generate errors for imports and the like. If ContainingSourceAssembly.DeclaringCompilation.Options.ConcurrentBuild Then Dim trees = ArrayBuilder(Of SyntaxTree).GetInstance() trees.AddRange(SyntaxTrees) RoslynParallel.For( 0, trees.Count, UICultureUtilities.WithCurrentUICulture( Sub(i As Integer) TryGetSourceFile(trees(i)).GenerateAllDeclarationErrors() End Sub), cancellationToken) trees.Free() Else For Each tree In SyntaxTrees cancellationToken.ThrowIfCancellationRequested() TryGetSourceFile(tree).GenerateAllDeclarationErrors() Next End If ' Force bind module and assembly attributes Dim unused = Me.GetAttributes() unused = Me.ContainingAssembly.GetAttributes() EnsureLinkedAssembliesAreValidated(cancellationToken) ' Force all types to generate errors. Dim tasks As ConcurrentStack(Of Task) = If(ContainingSourceAssembly.DeclaringCompilation.Options.ConcurrentBuild, New ConcurrentStack(Of Task)(), Nothing) VisitAllSourceTypesAndNamespaces(Sub(typeOrNamespace As NamespaceOrTypeSymbol) If typeOrNamespace.IsNamespace Then DirectCast(typeOrNamespace, SourceNamespaceSymbol).GenerateDeclarationErrors(cancellationToken) Else ' synthetic event delegates are not source types so use NamedTypeSymbol. Dim sourceType = DirectCast(typeOrNamespace, NamedTypeSymbol) sourceType.GenerateDeclarationErrors(cancellationToken) End If End Sub, tasks, cancellationToken) If tasks IsNot Nothing Then Dim curTask As Task = Nothing While tasks.TryPop(curTask) curTask.GetAwaiter().GetResult() End While End If ' At this point we should have recorded presence of extension methods. If _lazyContainsExtensionMethods = ThreeState.Unknown Then _lazyContainsExtensionMethods = ThreeState.False End If hasExtensionMethods = _lazyContainsExtensionMethods = ThreeState.True ' Accumulate all the errors that were generated. diagnostics.AddRange(Me._diagnosticBagDeclare) diagnostics.AddRange(Me._lazyBoundImports.Diagnostics, allowMismatchInDependencyAccumulation:=True) diagnostics.AddRange(Me._lazyBoundImportsAdditionalDiagnostics.Value, allowMismatchInDependencyAccumulation:=True) diagnostics.AddRange(Me._lazyLinkedAssemblyDiagnostics) For Each tree In SyntaxTrees diagnostics.AddRange(TryGetSourceFile(tree).DeclarationDiagnostics) Next End Sub ' Visit all of the source types within this source module. Private Sub VisitAllSourceTypesAndNamespaces(visitor As Action(Of NamespaceOrTypeSymbol), tasks As ConcurrentStack(Of Task), cancellationToken As CancellationToken) VisitTypesAndNamespacesWithin(Me.GlobalNamespace, visitor, tasks, cancellationToken) End Sub ' Visit all source types and namespaces within this source namespace or type, inclusive of this source namespace or type Private Sub VisitTypesAndNamespacesWithin(ns As NamespaceOrTypeSymbol, visitor As Action(Of NamespaceOrTypeSymbol), tasks As ConcurrentStack(Of Task), cancellationToken As CancellationToken) Dim stack = ArrayBuilder(Of NamespaceOrTypeSymbol).GetInstance Try stack.Push(ns) While stack.Count > 0 cancellationToken.ThrowIfCancellationRequested() Dim symbol = stack.Pop() If tasks IsNot Nothing Then Dim worker As Task = Task.Run( UICultureUtilities.WithCurrentUICulture( Sub() Try visitor(symbol) Catch e As Exception When FatalError.ReportAndPropagateUnlessCanceled(e) Throw ExceptionUtilities.Unreachable End Try End Sub), cancellationToken) tasks.Push(worker) Else visitor(symbol) End If For Each child As Symbol In If(symbol.IsNamespace, symbol.GetMembers(), symbol.GetTypeMembers().Cast(Of Symbol)) stack.Push(DirectCast(child, NamespaceOrTypeSymbol)) Next End While Finally stack.Free() End Try End Sub Private Sub EnsureLinkedAssembliesAreValidated(cancellationToken As CancellationToken) If _lazyLinkedAssemblyDiagnostics.IsDefault Then Dim diagnostics = DiagnosticBag.GetInstance() ValidateLinkedAssemblies(diagnostics, cancellationToken) ImmutableInterlocked.InterlockedInitialize(_lazyLinkedAssemblyDiagnostics, diagnostics.ToReadOnlyAndFree) End If End Sub Private Sub ValidateLinkedAssemblies(diagnostics As DiagnosticBag, cancellationToken As CancellationToken) For Each assembly In GetReferencedAssemblySymbols() cancellationToken.ThrowIfCancellationRequested() If assembly.IsMissing OrElse Not assembly.IsLinked Then Continue For End If If Not assembly.GetGuidString(Nothing) Then diagnostics.Add(ERRID.ERR_PIAHasNoAssemblyGuid1, NoLocation.Singleton, assembly, AttributeDescription.GuidAttribute.FullName) End If If Not assembly.HasImportedFromTypeLibAttribute AndAlso Not assembly.HasPrimaryInteropAssemblyAttribute Then diagnostics.Add(ERRID.ERR_PIAHasNoTypeLibAttribute1, NoLocation.Singleton, assembly, AttributeDescription.ImportedFromTypeLibAttribute.FullName, AttributeDescription.PrimaryInteropAssemblyAttribute.FullName) End If Next End Sub ' This lock is used in the implementation of AtomicStoreReferenceAndDiagnostics Private ReadOnly _diagnosticLock As New Object() ' Checks if the given diagnostic bag has all lazy obsolete diagnostics. Private Shared Function HasAllLazyDiagnostics(diagBag As DiagnosticBag) As Boolean Debug.Assert(diagBag IsNot Nothing) Debug.Assert(Not diagBag.IsEmptyWithoutResolution()) For Each diag In diagBag.AsEnumerable() Dim cdiag = TryCast(diag, DiagnosticWithInfo) If cdiag Is Nothing OrElse Not cdiag.HasLazyInfo Then Return False End If Next Return True End Function ''' <summary> ''' Atomically store value into variable, and store the diagnostics away for later retrieval. ''' When this routine returns, variable is non-null. If this routine stored value into variable, ''' then the diagnostic bag is saved away before the variable is stored and it returns True. ''' Otherwise it returns False. ''' </summary> Friend Function AtomicStoreReferenceAndDiagnostics(Of T As Class)(ByRef variable As T, value As T, diagBag As BindingDiagnosticBag, Optional comparand As T = Nothing) As Boolean Debug.Assert(value IsNot comparand) If diagBag Is Nothing OrElse diagBag.IsEmpty Then Return Interlocked.CompareExchange(variable, value, comparand) Is comparand AndAlso comparand Is Nothing Else Dim stored = False SyncLock _diagnosticLock If variable Is comparand Then StoreDeclarationDiagnostics(diagBag) stored = Interlocked.CompareExchange(variable, value, comparand) Is comparand If Not stored AndAlso Not IsEmptyIgnoringLazyDiagnostics(diagBag) Then ' If this gets hit, then someone wrote to variable without going through this ' routine, or else someone wrote to variable with this routine but an empty ' diagnostic bag (they went through the above If part). Either is a bug. Throw ExceptionUtilities.Unreachable End If End If End SyncLock Return stored AndAlso comparand Is Nothing End If End Function Private Shared Function IsEmptyIgnoringLazyDiagnostics(diagBag As BindingDiagnosticBag) As Boolean Return diagBag.DependenciesBag.IsNullOrEmpty() AndAlso (Not diagBag.AccumulatesDiagnostics OrElse HasAllLazyDiagnostics(diagBag.DiagnosticBag)) End Function ' Atomically store value into variable, and store the diagnostics away for later retrieval. ' When this routine returns, variable is not equal to comparand. If this routine stored value into variable, ' then the diagnostic bag is saved away before the variable is stored. Friend Sub AtomicStoreIntegerAndDiagnostics(ByRef variable As Integer, value As Integer, comparand As Integer, diagBag As BindingDiagnosticBag) If diagBag Is Nothing OrElse diagBag.IsEmpty Then Interlocked.CompareExchange(variable, value, comparand) Else SyncLock _diagnosticLock If variable = comparand Then StoreDeclarationDiagnostics(diagBag) If Interlocked.CompareExchange(variable, value, comparand) <> comparand AndAlso Not IsEmptyIgnoringLazyDiagnostics(diagBag) Then ' If this gets hit, then someone wrote to variable without going through this ' routine, or else someone wrote to variable with this routine but an empty ' diagnostic bag (they went through the above If part). Either is a bug. Throw ExceptionUtilities.Unreachable End If End If End SyncLock End If End Sub ' Atomically set flag value into variable, and store the diagnostics away for later retrieval. ' When this routine returns, variable is not equal to comparand. If this routine stored value into variable, ' then the diagnostic bag is saved away before the variable is stored. Friend Function AtomicSetFlagAndStoreDiagnostics(ByRef variable As Integer, mask As Integer, comparand As Integer, diagBag As BindingDiagnosticBag) As Boolean If diagBag Is Nothing OrElse diagBag.IsEmpty Then Return ThreadSafeFlagOperations.Set(variable, mask) Else SyncLock _diagnosticLock Dim change = (variable And mask) = comparand If change Then StoreDeclarationDiagnostics(diagBag) If Not ThreadSafeFlagOperations.Set(variable, mask) AndAlso Not IsEmptyIgnoringLazyDiagnostics(diagBag) Then ' If this gets hit, then someone wrote to variable without going through this ' routine, or else someone wrote to variable with this routine but an empty ' diagnostic bag (they went through the above If part). Either is a bug. Throw ExceptionUtilities.Unreachable End If End If Return change End SyncLock End If End Function ' Atomically set flag value into variable, and raise the symbol declared event. ' When this routine returns, variable is not equal to comparand. If this routine stored value into variable, ' then the symbol declared event was raised for the symbol. Friend Function AtomicSetFlagAndRaiseSymbolDeclaredEvent(ByRef variable As Integer, mask As Integer, comparand As Integer, symbol As Symbol) As Boolean Debug.Assert(Me.DeclaringCompilation.EventQueue IsNot Nothing) SyncLock _diagnosticLock Dim change = (variable And mask) = comparand If change Then Me.DeclaringCompilation.SymbolDeclaredEvent(symbol) If Not ThreadSafeFlagOperations.Set(variable, mask) Then ' If this gets hit, then someone wrote to variable without going through this ' routine, which is a bug. Throw ExceptionUtilities.Unreachable End If End If Return change End SyncLock End Function Friend Function AtomicStoreArrayAndDiagnostics(Of T)(ByRef variable As ImmutableArray(Of T), value As ImmutableArray(Of T), diagBag As BindingDiagnosticBag) As Boolean Debug.Assert(Not value.IsDefault) If diagBag Is Nothing OrElse diagBag.IsEmpty Then Return ImmutableInterlocked.InterlockedInitialize(variable, value) Else SyncLock _diagnosticLock If variable.IsDefault Then StoreDeclarationDiagnostics(diagBag) Dim stored = ImmutableInterlocked.InterlockedInitialize(variable, value) If Not stored AndAlso Not IsEmptyIgnoringLazyDiagnostics(diagBag) Then ' If this gets hit, then someone wrote to variable without going through this ' routine, or else someone wrote to variable with this routine but an empty ' diagnostic bag (they went through the above If part). Either is a bug. Throw ExceptionUtilities.Unreachable End If Return stored Else Return False End If End SyncLock End If End Function Friend Sub AtomicStoreAttributesAndDiagnostics(attributesBag As CustomAttributesBag(Of VisualBasicAttributeData), attributesToStore As ImmutableArray(Of VisualBasicAttributeData), diagBag As BindingDiagnosticBag) Debug.Assert(attributesBag IsNot Nothing) Debug.Assert(Not attributesToStore.IsDefault) RecordPresenceOfBadAttributes(attributesToStore) If diagBag Is Nothing OrElse diagBag.IsEmpty Then attributesBag.SetAttributes(attributesToStore) Else SyncLock _diagnosticLock If Not attributesBag.IsSealed Then StoreDeclarationDiagnostics(diagBag) If Not attributesBag.SetAttributes(attributesToStore) AndAlso Not IsEmptyIgnoringLazyDiagnostics(diagBag) Then ' If this gets hit, then someone set attributes in the bag without going through this ' routine, or else someone set attributes in the bag with this routine but an empty ' diagnostic bag (they went through the above If part). Either is a bug. Throw ExceptionUtilities.Unreachable End If Debug.Assert(attributesBag.IsSealed) End If End SyncLock End If End Sub Private Sub RecordPresenceOfBadAttributes(attributes As ImmutableArray(Of VisualBasicAttributeData)) If Not _hasBadAttributes Then For Each attribute In attributes If attribute.HasErrors Then _hasBadAttributes = True Exit For End If Next End If End Sub Friend ReadOnly Property HasBadAttributes As Boolean Get Return _hasBadAttributes End Get End Property ' same as AtomicStoreReferenceAndDiagnostics, but without storing any references Friend Sub AddDeclarationDiagnostics(diagBag As BindingDiagnosticBag) If Not diagBag.IsEmpty Then SyncLock _diagnosticLock StoreDeclarationDiagnostics(diagBag) End SyncLock End If End Sub ' Given a diagnostic bag, store the diagnostics into the correct bags. ' NOTE: This is called from AtomicStoreReferenceAndDiagnostics, which takes a lock. ' NOTE: It is important that it doesn't do any operation that wants to acquire another lock. ' NOTE: Copy without resolving diagnostics. Private Sub StoreDeclarationDiagnostics(diagBag As BindingDiagnosticBag) If Not diagBag.IsEmpty Then If Not diagBag.DiagnosticBag?.IsEmptyWithoutResolution Then For Each d As Diagnostic In diagBag.DiagnosticBag.AsEnumerableWithoutResolution() Dim loc = d.Location If loc.IsInSource Then Dim tree = DirectCast(loc.SourceTree, VisualBasicSyntaxTree) Dim sourceFile = TryGetSourceFile(tree) Debug.Assert(sourceFile IsNot Nothing) sourceFile.DeclarationDiagnostics.Add(d) Else Me._diagnosticBagDeclare.Add(d) End If Next End If If Not diagBag.DependenciesBag.IsNullOrEmpty() Then DeclaringCompilation.AddUsedAssemblies(diagBag.DependenciesBag) End If End If End Sub Friend Overrides ReadOnly Property TypeNames As ICollection(Of String) Get Return _declarationTable.TypeNames End Get End Property Friend Overrides ReadOnly Property NamespaceNames As ICollection(Of String) Get Return _declarationTable.NamespaceNames End Get End Property Friend Overrides ReadOnly Property MightContainExtensionMethods As Boolean Get ' Only primary module of an assembly marked with an Extension attribute ' can contain extension methods recognized by the language (Dev10 behavior). If _lazyContainsExtensionMethods = ThreeState.Unknown Then If Not (_assemblySymbol.Modules(0) Is Me) Then _lazyContainsExtensionMethods = ThreeState.False End If End If Return _lazyContainsExtensionMethods <> ThreeState.False End Get End Property Friend Sub RecordPresenceOfExtensionMethods() Debug.Assert(_lazyContainsExtensionMethods <> ThreeState.False) _lazyContainsExtensionMethods = ThreeState.True End Sub Friend Overrides Sub DecodeWellKnownAttribute(ByRef arguments As DecodeWellKnownAttributeArguments(Of AttributeSyntax, VisualBasicAttributeData, AttributeLocation)) Debug.Assert(arguments.AttributeSyntaxOpt IsNot Nothing) Dim attrData = arguments.Attribute Debug.Assert(Not attrData.HasErrors) Debug.Assert(arguments.SymbolPart = AttributeLocation.None) If attrData.IsTargetAttribute(AttributeDescription.TupleElementNamesAttribute) Then DirectCast(arguments.Diagnostics, BindingDiagnosticBag).Add(ERRID.ERR_ExplicitTupleElementNamesAttribute, arguments.AttributeSyntaxOpt.Location) End If If attrData.IsTargetAttribute(AttributeDescription.DefaultCharSetAttribute) Then Dim charSet As CharSet = attrData.GetConstructorArgument(Of CharSet)(0, SpecialType.System_Enum) If Not CommonModuleWellKnownAttributeData.IsValidCharSet(charSet) Then DirectCast(arguments.Diagnostics, BindingDiagnosticBag).Add(ERRID.ERR_BadAttribute1, VisualBasicAttributeData.GetFirstArgumentLocation(arguments.AttributeSyntaxOpt), attrData.AttributeClass) Else arguments.GetOrCreateData(Of CommonModuleWellKnownAttributeData)().DefaultCharacterSet = charSet End If ElseIf attrData.IsTargetAttribute(AttributeDescription.DebuggableAttribute) Then arguments.GetOrCreateData(Of CommonModuleWellKnownAttributeData).HasDebuggableAttribute = True ElseIf attrData.IsTargetAttribute(AttributeDescription.ExperimentalAttribute) Then arguments.GetOrCreateData(Of CommonModuleWellKnownAttributeData).ExperimentalAttributeData = attrData.DecodeObsoleteAttribute(ObsoleteAttributeKind.Experimental) End If MyBase.DecodeWellKnownAttribute(arguments) End Sub Friend Overrides ReadOnly Property HasAssemblyCompilationRelaxationsAttribute() As Boolean Get Dim decodedData As CommonAssemblyWellKnownAttributeData(Of NamedTypeSymbol) = DirectCast(Me.ContainingAssembly, SourceAssemblySymbol).GetSourceDecodedWellKnownAttributeData() Return decodedData IsNot Nothing AndAlso decodedData.HasCompilationRelaxationsAttribute End Get End Property Friend Overrides ReadOnly Property HasAssemblyRuntimeCompatibilityAttribute() As Boolean Get Dim decodedData As CommonAssemblyWellKnownAttributeData(Of NamedTypeSymbol) = DirectCast(Me.ContainingAssembly, SourceAssemblySymbol).GetSourceDecodedWellKnownAttributeData() Return decodedData IsNot Nothing AndAlso decodedData.HasRuntimeCompatibilityAttribute End Get End Property Friend Overrides ReadOnly Property DefaultMarshallingCharSet As CharSet? Get Dim data = GetDecodedWellKnownAttributeData() Return If(data IsNot Nothing AndAlso data.HasDefaultCharSetAttribute, data.DefaultCharacterSet, DirectCast(Nothing, CharSet?)) End Get End Property Public Function GetMyGroupCollectionPropertyWithDefaultInstanceAlias(classType As NamedTypeSymbol) As SynthesizedMyGroupCollectionPropertySymbol Debug.Assert(classType.IsDefinition AndAlso Not classType.IsGenericType) If _lazyTypesWithDefaultInstanceAlias Is Nothing Then _lazyTypesWithDefaultInstanceAlias = GetTypesWithDefaultInstanceAlias() End If Dim result As SynthesizedMyGroupCollectionPropertySymbol = Nothing If _lazyTypesWithDefaultInstanceAlias IsNot s_noTypesWithDefaultInstanceAlias AndAlso _lazyTypesWithDefaultInstanceAlias.TryGetValue(classType, result) Then Return result End If Return Nothing End Function Private Function GetTypesWithDefaultInstanceAlias() As Dictionary(Of NamedTypeSymbol, SynthesizedMyGroupCollectionPropertySymbol) Dim result As Dictionary(Of NamedTypeSymbol, SynthesizedMyGroupCollectionPropertySymbol) = Nothing If _assemblySymbol.DeclaringCompilation.MyTemplate IsNot Nothing Then GetTypesWithDefaultInstanceAlias(GlobalNamespace, result) End If If result Is Nothing Then result = s_noTypesWithDefaultInstanceAlias End If Return result End Function Private Shared Sub GetTypesWithDefaultInstanceAlias( namespaceOrType As NamespaceOrTypeSymbol, <[In], Out> ByRef result As Dictionary(Of NamedTypeSymbol, SynthesizedMyGroupCollectionPropertySymbol) ) For Each member As Symbol In namespaceOrType.GetMembersUnordered() Select Case member.Kind Case SymbolKind.Property If member.IsMyGroupCollectionProperty Then Dim prop = DirectCast(member, SynthesizedMyGroupCollectionPropertySymbol) ' See Semantics::GetDefaultInstanceBaseNameForMyGroupMember If prop.DefaultInstanceAlias.Length > 0 Then Dim targetType = DirectCast(prop.Type, NamedTypeSymbol) If result Is Nothing Then result = New Dictionary(Of NamedTypeSymbol, SynthesizedMyGroupCollectionPropertySymbol)(ReferenceEqualityComparer.Instance) ElseIf result.ContainsKey(targetType) Then ' ambiguity result(targetType) = Nothing Exit Select End If result.Add(targetType, prop) End If End If Case SymbolKind.NamedType Dim named = TryCast(member, SourceNamedTypeSymbol) If named IsNot Nothing Then For Each syntaxRef As SyntaxReference In named.SyntaxReferences If syntaxRef.SyntaxTree.IsMyTemplate Then GetTypesWithDefaultInstanceAlias(named, result) Exit For End If Next End If Case SymbolKind.Namespace GetTypesWithDefaultInstanceAlias(DirectCast(member, NamespaceSymbol), result) End Select Next End Sub Public Overrides Function GetMetadata() As ModuleMetadata Return Nothing End Function Friend Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData Get Dim attributesBag As CustomAttributesBag(Of VisualBasicAttributeData) = Me._lazyCustomAttributesBag If attributesBag IsNot Nothing AndAlso attributesBag.IsDecodedWellKnownAttributeDataComputed Then Return DirectCast(attributesBag.DecodedWellKnownAttributeData, CommonModuleWellKnownAttributeData)?.ExperimentalAttributeData End If Dim mergedAttributes = DirectCast(Me.ContainingAssembly, SourceAssemblySymbol).GetAttributeDeclarations() If mergedAttributes.IsEmpty Then Return Nothing End If Return ObsoleteAttributeData.Uninitialized End Get End Property End Class End Namespace