/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Features/VisualBasic/Portable/NavigationBar/VisualBasicNavigationBarItemService.vb
458 строк
22 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.Composition Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.ErrorReporting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.NavigationBar.RoslynNavigationBarItem Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.NavigationBar <ExportLanguageService(GetType(INavigationBarItemService), LanguageNames.VisualBasic), [Shared]> Partial Friend NotInheritable Class VisualBasicNavigationBarItemService Inherits AbstractNavigationBarItemService Private ReadOnly _typeFormat As SymbolDisplayFormat = New SymbolDisplayFormat( genericsOptions:=SymbolDisplayGenericsOptions.IncludeTypeParameters Or SymbolDisplayGenericsOptions.IncludeVariance) Private ReadOnly _memberFormat As SymbolDisplayFormat = New SymbolDisplayFormat( genericsOptions:=SymbolDisplayGenericsOptions.IncludeTypeParameters, memberOptions:=SymbolDisplayMemberOptions.IncludeParameters Or SymbolDisplayMemberOptions.IncludeType, parameterOptions:=SymbolDisplayParameterOptions.IncludeType, miscellaneousOptions:=SymbolDisplayMiscellaneousOptions.UseSpecialTypes) <ImportingConstructor> <Obsolete(MefConstruction.ImportingConstructorMessage, True)> Public Sub New() End Sub Protected Overrides Async Function GetItemsInCurrentProcessAsync( document As Document, workspaceSupportsDocumentChanges As Boolean, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of RoslynNavigationBarItem)) Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) Contract.ThrowIfNull(semanticModel) Dim typesAndDeclarations = GetTypesAndDeclarationsInFile(semanticModel, cancellationToken) Dim typeItems = ImmutableArray.CreateBuilder(Of RoslynNavigationBarItem) Dim symbolDeclarationService = document.GetLanguageService(Of ISymbolDeclarationService) For Each typeAndDeclaration In typesAndDeclarations Dim type = typeAndDeclaration.Item1 Dim position = typeAndDeclaration.Item2.SpanStart typeItems.AddRange(CreateItemsForType( document.Project.Solution, type, position, semanticModel, workspaceSupportsDocumentChanges, symbolDeclarationService, cancellationToken)) Next Return typeItems.ToImmutable() End Function Private Shared Function GetTypesAndDeclarationsInFile(semanticModel As SemanticModel, cancellationToken As CancellationToken) As IEnumerable(Of Tuple(Of INamedTypeSymbol, SyntaxNode)) Try Dim typesAndDeclarations As New Dictionary(Of INamedTypeSymbol, SyntaxNode) Dim nodesToVisit As New Stack(Of SyntaxNode) nodesToVisit.Push(DirectCast(semanticModel.SyntaxTree.GetRoot(cancellationToken), SyntaxNode)) Do Until nodesToVisit.IsEmpty If cancellationToken.IsCancellationRequested Then Return SpecializedCollections.EmptyEnumerable(Of Tuple(Of INamedTypeSymbol, SyntaxNode))() End If Dim node = nodesToVisit.Pop() Dim type = TryCast(semanticModel.GetDeclaredSymbol(node, cancellationToken), INamedTypeSymbol) If type IsNot Nothing Then typesAndDeclarations(type) = node End If If TypeOf node Is MethodBlockBaseSyntax OrElse TypeOf node Is PropertyBlockSyntax OrElse TypeOf node Is EventBlockSyntax OrElse TypeOf node Is FieldDeclarationSyntax OrElse TypeOf node Is ExecutableStatementSyntax OrElse TypeOf node Is ExpressionSyntax Then ' quick bail out to prevent us from creating every nodes exist in current file Continue Do End If For Each child In node.ChildNodes() nodesToVisit.Push(child) Next Loop Return typesAndDeclarations.Select(Function(kvp) Tuple.Create(kvp.Key, kvp.Value)).OrderBy(Function(t) t.Item1.Name) Catch ex As Exception When FatalError.ReportAndPropagateUnlessCanceled(ex, cancellationToken) Throw ExceptionUtilities.Unreachable End Try End Function Private Function CreateItemsForType( solution As Solution, type As INamedTypeSymbol, position As Integer, semanticModel As SemanticModel, workspaceSupportsDocumentChanges As Boolean, symbolDeclarationService As ISymbolDeclarationService, cancellationToken As CancellationToken) As ImmutableArray(Of RoslynNavigationBarItem) Dim items = ArrayBuilder(Of RoslynNavigationBarItem).GetInstance() If type.TypeKind = TypeKind.Enum Then items.AddIfNotNull(CreateItemForEnum(solution, type, semanticModel.SyntaxTree, symbolDeclarationService)) Else items.AddIfNotNull(CreatePrimaryItemForType(solution, type, semanticModel.SyntaxTree, workspaceSupportsDocumentChanges, symbolDeclarationService, cancellationToken)) If type.TypeKind <> TypeKind.Interface Then Dim typeEvents = CreateItemForEvents( solution, type, position, type, eventContainer:=Nothing, semanticModel:=semanticModel, workspaceSupportsDocumentChanges:=workspaceSupportsDocumentChanges, symbolDeclarationService:=symbolDeclarationService, cancellationToken) ' Add the (<ClassName> Events) item only if it actually has things within it If typeEvents.ChildItems.Count > 0 Then items.Add(typeEvents) End If For Each member In type.GetMembers().OrderBy(Function(m) m.Name) ' If this is a WithEvents property, then we should also add items for it Dim propertySymbol = TryCast(member, IPropertySymbol) If propertySymbol IsNot Nothing AndAlso propertySymbol.IsWithEvents Then items.AddIfNotNull(CreateItemForEvents( solution, type, position, propertySymbol.Type, propertySymbol, semanticModel, workspaceSupportsDocumentChanges, symbolDeclarationService, cancellationToken)) End If Next End If End If Return items.ToImmutableAndFree() End Function Private Shared Function CreateItemForEnum( solution As Solution, type As INamedTypeSymbol, tree As SyntaxTree, symbolDeclarationService As ISymbolDeclarationService) As RoslynNavigationBarItem Dim members = From member In type.GetMembers() Where member.IsShared AndAlso member.Kind = Global.Microsoft.CodeAnalysis.SymbolKind.Field Order By member.Name Select CreateSymbolItem(solution, member, tree, symbolDeclarationService) Dim location = GetSymbolLocation(solution, type, tree, symbolDeclarationService) If location Is Nothing Then Return Nothing End If Return New SymbolItem( type.Name, type.Name, type.GetGlyph(), type.IsObsolete, location.Value, ImmutableArray(Of RoslynNavigationBarItem).CastUp(members.WhereNotNull().ToImmutableArray()), bolded:=True) End Function Private Shared Function CreateSymbolItem( solution As Solution, member As ISymbol, tree As SyntaxTree, symbolDeclarationService As ISymbolDeclarationService) As SymbolItem Dim location = GetSymbolLocation(solution, member, tree, symbolDeclarationService) If location Is Nothing Then Return Nothing End If Return New SymbolItem( member.Name, member.Name, member.GetGlyph(), member.IsObsolete, location.Value) End Function Private Function CreatePrimaryItemForType( solution As Solution, type As INamedTypeSymbol, tree As SyntaxTree, workspaceSupportsDocumentChanges As Boolean, symbolDeclarationService As ISymbolDeclarationService, cancellationToken As CancellationToken) As RoslynNavigationBarItem Dim childItems As New List(Of RoslynNavigationBarItem) ' First, we always list the constructors Dim constructors = type.Constructors If constructors.All(Function(c) c.IsImplicitlyDeclared) Then ' Offer to generate the constructor only if it's legal If workspaceSupportsDocumentChanges AndAlso type.TypeKind = TypeKind.Class Then childItems.Add(New GenerateDefaultConstructor("New", type.GetSymbolKey(cancellationToken))) End If Else childItems.AddRange(CreateItemsForMemberGroup(solution, constructors, tree, workspaceSupportsDocumentChanges, symbolDeclarationService, cancellationToken)) End If ' Get any of the methods named "Finalize" in this class, and list them first. The legacy ' behavior that we will consider a method a finalizer even if it is shadowing the real ' Finalize method instead of overriding it, so this code is actually correct! Dim finalizeMethods = type.GetMembers(WellKnownMemberNames.DestructorName) If Not finalizeMethods.Any() Then If workspaceSupportsDocumentChanges AndAlso type.TypeKind = TypeKind.Class Then childItems.Add(New GenerateFinalizer(WellKnownMemberNames.DestructorName, type.GetSymbolKey(cancellationToken))) End If Else childItems.AddRange(CreateItemsForMemberGroup(solution, finalizeMethods, tree, workspaceSupportsDocumentChanges, symbolDeclarationService, cancellationToken)) End If ' And now, methods and properties If type.TypeKind <> TypeKind.Delegate Then Dim memberGroups = type.GetMembers().Where(AddressOf IncludeMember) _ .GroupBy(Function(m) m.Name, CaseInsensitiveComparison.Comparer) _ .OrderBy(Function(g) g.Key) For Each memberGroup In memberGroups If Not CaseInsensitiveComparison.Equals(memberGroup.Key, WellKnownMemberNames.DestructorName) Then childItems.AddRange(CreateItemsForMemberGroup(solution, memberGroup, tree, workspaceSupportsDocumentChanges, symbolDeclarationService, cancellationToken)) End If Next End If Dim name = type.ToDisplayString(_typeFormat) If type.ContainingType IsNot Nothing Then name &= " (" & type.ContainingType.ToDisplayString() & ")" End If Dim location = GetSymbolLocation(solution, type, tree, symbolDeclarationService) If location Is Nothing Then Return Nothing End If Return New SymbolItem( type.Name, name, type.GetGlyph(), type.IsObsolete, location.Value, childItems:=childItems.ToImmutableArray(), bolded:=True) End Function Private Shared Function IncludeMember(symbol As ISymbol) As Boolean If symbol.Kind = SymbolKind.Method Then Dim method = DirectCast(symbol, IMethodSymbol) If method.HandledEvents.Any() Then Return False End If Return method.MethodKind = MethodKind.Ordinary OrElse method.MethodKind = MethodKind.UserDefinedOperator OrElse method.MethodKind = MethodKind.Conversion End If If symbol.Kind = SymbolKind.Property Then Dim p = DirectCast(symbol, IPropertySymbol) Return Not p.IsWithEvents End If If symbol.Kind = SymbolKind.Event Then Return True End If If symbol.Kind = SymbolKind.Field AndAlso Not symbol.IsImplicitlyDeclared Then Return True End If Return False End Function ''' <summary> ''' Creates the left-hand entry and right-hand entries for a list of events. ''' </summary> ''' <param name="containingType">The type that contains the methods attached to the events. ''' For items that will generate new methods, they will be generated into this ''' class.</param> ''' <param name="eventType">The type to list the events of. This is either equal to ''' containingType if it's listing the event handlers for the base types, or else it's the ''' type of the eventContainer.</param> ''' <param name="eventContainer">If this is an entry for a WithEvents member, the WithEvents ''' property itself.</param> Private Shared Function CreateItemForEvents( solution As Solution, containingType As INamedTypeSymbol, position As Integer, eventType As ITypeSymbol, eventContainer As IPropertySymbol, semanticModel As SemanticModel, workspaceSupportsDocumentChanges As Boolean, symbolDeclarationService As ISymbolDeclarationService, cancellationToken As CancellationToken) As RoslynNavigationBarItem Dim rightHandMemberItems As New List(Of RoslynNavigationBarItem) Dim accessibleEvents = semanticModel.LookupSymbols(position, eventType).OfType(Of IEventSymbol).OrderBy(Function(e) e.Name) Dim methodsImplementingEvents = containingType.GetMembers().OfType(Of IMethodSymbol) _ .Where(Function(m) m.HandledEvents.Any(Function(he) Object.Equals(he.EventContainer, eventContainer))) Dim eventToImplementingMethods As New Dictionary(Of IEventSymbol, List(Of IMethodSymbol)) For Each method In methodsImplementingEvents For Each handledEvent In method.HandledEvents Dim list As List(Of IMethodSymbol) = Nothing If Not eventToImplementingMethods.TryGetValue(handledEvent.EventSymbol, list) Then list = New List(Of IMethodSymbol) eventToImplementingMethods.Add(handledEvent.EventSymbol, list) End If list.Add(method) Next Next ' Generate an item for each event For Each e In accessibleEvents Dim methods As List(Of IMethodSymbol) = Nothing If eventToImplementingMethods.TryGetValue(e, methods) Then Dim methodLocation = GetSymbolLocation(solution, methods.First(), semanticModel.SyntaxTree, symbolDeclarationService) If methodLocation IsNot Nothing Then rightHandMemberItems.Add(New SymbolItem( e.Name, e.Name, e.GetGlyph(), e.IsObsolete, methodLocation.Value, bolded:=True)) End If Else If workspaceSupportsDocumentChanges AndAlso e.Type IsNot Nothing AndAlso e.Type.IsDelegateType() AndAlso DirectCast(e.Type, INamedTypeSymbol).DelegateInvokeMethod IsNot Nothing Then Dim eventContainerName = eventContainer?.Name rightHandMemberItems.Add( New GenerateEventHandler( e.Name, e.GetGlyph(), eventContainerName, e.GetSymbolKey(cancellationToken), containingType.GetSymbolKey(cancellationToken))) End If End If Next If eventContainer IsNot Nothing Then Return New ActionlessItem( eventContainer.Name, eventContainer.GetGlyph(), indent:=1, childItems:=rightHandMemberItems.ToImmutableArray()) Else Return New ActionlessItem( String.Format(VBFeaturesResources._0_Events, containingType.Name), Glyph.EventPublic, indent:=1, childItems:=rightHandMemberItems.ToImmutableArray()) End If End Function Private Function CreateItemsForMemberGroup( solution As Solution, members As IEnumerable(Of ISymbol), tree As SyntaxTree, workspaceSupportsDocumentChanges As Boolean, symbolDeclarationService As ISymbolDeclarationService, cancellationToken As CancellationToken) As IEnumerable(Of RoslynNavigationBarItem) Dim firstMember = members.First() ' If there is exactly one member that has no type arguments, we will skip showing the ' parameters for it to maintain behavior with Dev11 Dim displayFormat = If(members.Count() = 1 AndAlso firstMember.GetArity() = 0, New SymbolDisplayFormat(), _memberFormat) ' If we're doing operators, we want to include the keyword If firstMember.IsUserDefinedOperator OrElse firstMember.IsConversion Then displayFormat = displayFormat.WithKindOptions(displayFormat.KindOptions Or SymbolDisplayKindOptions.IncludeMemberKeyword) End If Dim items As New List(Of RoslynNavigationBarItem) For Each member In members ' If this is a partial method, we'll care about the implementation part if one ' exists Dim method = TryCast(member, IMethodSymbol) If method IsNot Nothing AndAlso method.PartialImplementationPart IsNot Nothing Then method = method.PartialImplementationPart Dim location = GetSymbolLocation(solution, method, tree, symbolDeclarationService) If location IsNot Nothing Then items.Add(New SymbolItem( method.Name, method.ToDisplayString(displayFormat), method.GetGlyph(), method.IsObsolete, location.Value, bolded:=location.Value.InDocumentInfo IsNot Nothing)) End If ElseIf method IsNot Nothing AndAlso IsUnimplementedPartial(method) Then If workspaceSupportsDocumentChanges Then items.Add(New GenerateMethod( member.ToDisplayString(displayFormat), member.GetGlyph(), member.ContainingType.GetSymbolKey(cancellationToken), member.GetSymbolKey(cancellationToken))) End If Else Dim location = GetSymbolLocation(solution, member, tree, symbolDeclarationService) If location IsNot Nothing Then items.Add(New SymbolItem( member.Name, member.ToDisplayString(displayFormat), member.GetGlyph(), member.IsObsolete, location.Value, bolded:=location.Value.InDocumentInfo IsNot Nothing)) End If End If Next Return items.OrderBy(Function(i) i.Text) End Function Private Shared Function IsUnimplementedPartial(method As IMethodSymbol) As Boolean If method.PartialImplementationPart IsNot Nothing Then Return False End If Return method.DeclaringSyntaxReferences.Select(Function(r) r.GetSyntax()).OfType(Of MethodStatementSyntax)().Any(Function(m) m.Modifiers.Any(Function(t) t.Kind = SyntaxKind.PartialKeyword)) End Function End Class End Namespace