77using System . Collections . Immutable ;
88using System . Composition ;
99using System . Diagnostics ;
10+ using System . Linq ;
1011using System . Threading ;
1112using System . Threading . Tasks ;
13+ using Microsoft . CodeAnalysis . CSharp . Extensions ;
14+ using Microsoft . CodeAnalysis . CSharp . LanguageService ;
1215using Microsoft . CodeAnalysis . CSharp . Syntax ;
16+ using Microsoft . CodeAnalysis . Elfie . Model ;
1317using Microsoft . CodeAnalysis . Host . Mef ;
1418using Microsoft . CodeAnalysis . Internal . Log ;
19+ using Microsoft . CodeAnalysis . LanguageService ;
1520using Microsoft . CodeAnalysis . NavigationBar ;
1621using Microsoft . CodeAnalysis . PooledObjects ;
1722using Microsoft . CodeAnalysis . Shared . Extensions ;
@@ -54,11 +59,11 @@ protected override async Task<ImmutableArray<RoslynNavigationBarItem>> GetItemsI
5459 if ( cancellationToken . IsCancellationRequested )
5560 return [ ] ;
5661
57- return GetMembersInTypes ( document . Project . Solution , semanticModel . SyntaxTree , typesInFile , cancellationToken ) ;
62+ return GetMembersInTypes ( document . Project . Solution , semanticModel . SyntaxTree , typesInFile , semanticModel , cancellationToken ) ;
5863 }
5964
6065 private static ImmutableArray < RoslynNavigationBarItem > GetMembersInTypes (
61- Solution solution , SyntaxTree tree , HashSet < INamedTypeSymbol > types , CancellationToken cancellationToken )
66+ Solution solution , SyntaxTree tree , HashSet < INamedTypeSymbol > types , SemanticModel semanticModel , CancellationToken cancellationToken )
6267 {
6368 using ( Logger . LogBlock ( FunctionId . NavigationBar_ItemService_GetMembersInTypes_CSharp , cancellationToken ) )
6469 {
@@ -79,29 +84,29 @@ private static ImmutableArray<RoslynNavigationBarItem> GetMembersInTypes(
7984
8085 if ( member is IMethodSymbol { PartialImplementationPart : { } } methodSymbol )
8186 {
82- memberItems . AddIfNotNull ( CreateItemForMember ( solution , methodSymbol , tree , cancellationToken ) ) ;
83- memberItems . AddIfNotNull ( CreateItemForMember ( solution , methodSymbol . PartialImplementationPart , tree , cancellationToken ) ) ;
87+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , methodSymbol , tree , semanticModel , cancellationToken ) ) ;
88+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , methodSymbol . PartialImplementationPart , tree , semanticModel , cancellationToken ) ) ;
8489 }
8590 else if ( member is IPropertySymbol { PartialImplementationPart : { } } propertySymbol )
8691 {
87- memberItems . AddIfNotNull ( CreateItemForMember ( solution , propertySymbol , tree , cancellationToken ) ) ;
88- memberItems . AddIfNotNull ( CreateItemForMember ( solution , propertySymbol . PartialImplementationPart , tree , cancellationToken ) ) ;
92+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , propertySymbol , tree , semanticModel , cancellationToken ) ) ;
93+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , propertySymbol . PartialImplementationPart , tree , semanticModel , cancellationToken ) ) ;
8994 }
9095 else if ( member is IEventSymbol { PartialImplementationPart : { } } eventSymbol )
9196 {
92- memberItems . AddIfNotNull ( CreateItemForMember ( solution , eventSymbol , tree , cancellationToken ) ) ;
93- memberItems . AddIfNotNull ( CreateItemForMember ( solution , eventSymbol . PartialImplementationPart , tree , cancellationToken ) ) ;
97+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , eventSymbol , tree , semanticModel , cancellationToken ) ) ;
98+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , eventSymbol . PartialImplementationPart , tree , semanticModel , cancellationToken ) ) ;
9499 }
95100 else if ( member is IMethodSymbol or IPropertySymbol or IEventSymbol )
96101 {
97102 Debug . Assert ( member is IMethodSymbol { PartialDefinitionPart : null } or IPropertySymbol { PartialDefinitionPart : null } or IEventSymbol { PartialDefinitionPart : null } ,
98103 $ "NavBar expected GetMembers to return partial method/property/event definition parts but the implementation part was returned.") ;
99104
100- memberItems . AddIfNotNull ( CreateItemForMember ( solution , member , tree , cancellationToken ) ) ;
105+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , member , tree , semanticModel , cancellationToken ) ) ;
101106 }
102107 else
103108 {
104- memberItems . AddIfNotNull ( CreateItemForMember ( solution , member , tree , cancellationToken ) ) ;
109+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , member , tree , semanticModel , cancellationToken ) ) ;
105110 }
106111 }
107112
@@ -166,6 +171,7 @@ StatementSyntax or
166171 {
167172 BaseTypeDeclarationSyntax t => semanticModel . GetDeclaredSymbol ( t , cancellationToken ) ,
168173 DelegateDeclarationSyntax d => semanticModel . GetDeclaredSymbol ( d , cancellationToken ) ,
174+ CompilationUnitSyntax c => c . IsTopLevelProgram ( ) ? semanticModel . GetDeclaredSymbol ( c , cancellationToken ) ? . ContainingType : null ,
169175 _ => null ,
170176 } ;
171177
@@ -182,18 +188,41 @@ private static bool IsAccessor(ISymbol member)
182188 }
183189
184190 private static SymbolItem ? CreateItemForMember (
185- Solution solution , ISymbol member , SyntaxTree tree , CancellationToken cancellationToken )
191+ Solution solution , ISymbol member , SyntaxTree tree , SemanticModel semanticModel , CancellationToken cancellationToken )
186192 {
187193 var location = GetSymbolLocation ( solution , member , tree , cancellationToken ) ;
188194 if ( location == null )
189195 return null ;
190196
197+ using var _ = ArrayBuilder < RoslynNavigationBarItem > . GetInstance ( out var localFunctionItems ) ;
198+ foreach ( var syntaxReference in member . DeclaringSyntaxReferences )
199+ {
200+ if ( syntaxReference . SyntaxTree != tree )
201+ {
202+ // The reference is not in this file, no need to include in the outline view.
203+ continue ;
204+ }
205+
206+ var node = syntaxReference . GetSyntax ( cancellationToken ) ;
207+ foreach ( var localFunction in node . DescendantNodes ( ) . Where ( CSharpSyntaxFacts . Instance . IsLocalFunctionStatement ) )
208+ {
209+ var localFunctionSymbol = semanticModel . GetDeclaredSymbol ( localFunction , cancellationToken ) ;
210+ // Check to make sure we only include local functions that are directly contained in the current member.
211+ // We'll recursively add any nested local functions when we traverse the direct descendent.
212+ if ( localFunctionSymbol is IMethodSymbol && localFunctionSymbol . ContainingSymbol == member )
213+ {
214+ localFunctionItems . AddIfNotNull ( CreateItemForMember ( solution , localFunctionSymbol , tree , semanticModel , cancellationToken ) ) ;
215+ }
216+ }
217+ }
218+
191219 return new SymbolItem (
192220 member . ToDisplayString ( s_memberNameFormat ) ,
193221 member . ToDisplayString ( s_memberDetailsFormat ) ,
194222 member . GetGlyph ( ) ,
195223 member . IsObsolete ( ) ,
196- location . Value ) ;
224+ location . Value ,
225+ localFunctionItems . ToImmutable ( ) ) ;
197226 }
198227
199228 private static SymbolItemLocation ? GetSymbolLocation (
0 commit comments