7
7
using System . Collections . Immutable ;
8
8
using System . Composition ;
9
9
using System . Diagnostics ;
10
+ using System . Linq ;
10
11
using System . Threading ;
11
12
using System . Threading . Tasks ;
13
+ using Microsoft . CodeAnalysis . CSharp . Extensions ;
12
14
using Microsoft . CodeAnalysis . CSharp . Syntax ;
13
15
using Microsoft . CodeAnalysis . Host . Mef ;
14
16
using Microsoft . CodeAnalysis . Internal . Log ;
@@ -54,14 +56,15 @@ protected override async Task<ImmutableArray<RoslynNavigationBarItem>> GetItemsI
54
56
if ( cancellationToken . IsCancellationRequested )
55
57
return [ ] ;
56
58
57
- return GetMembersInTypes ( document . Project . Solution , semanticModel . SyntaxTree , typesInFile , cancellationToken ) ;
59
+ return GetMembersInTypes ( document . Project . Solution , semanticModel , typesInFile , cancellationToken ) ;
58
60
}
59
61
60
62
private static ImmutableArray < RoslynNavigationBarItem > GetMembersInTypes (
61
- Solution solution , SyntaxTree tree , HashSet < INamedTypeSymbol > types , CancellationToken cancellationToken )
63
+ Solution solution , SemanticModel semanticModel , HashSet < INamedTypeSymbol > types , CancellationToken cancellationToken )
62
64
{
63
65
using ( Logger . LogBlock ( FunctionId . NavigationBar_ItemService_GetMembersInTypes_CSharp , cancellationToken ) )
64
66
{
67
+ var tree = semanticModel . SyntaxTree ;
65
68
using var _1 = ArrayBuilder < RoslynNavigationBarItem > . GetInstance ( out var items ) ;
66
69
67
70
foreach ( var type in types )
@@ -79,29 +82,29 @@ private static ImmutableArray<RoslynNavigationBarItem> GetMembersInTypes(
79
82
80
83
if ( member is IMethodSymbol { PartialImplementationPart : { } } methodSymbol )
81
84
{
82
- memberItems . AddIfNotNull ( CreateItemForMember ( solution , methodSymbol , tree , cancellationToken ) ) ;
83
- memberItems . AddIfNotNull ( CreateItemForMember ( solution , methodSymbol . PartialImplementationPart , tree , cancellationToken ) ) ;
85
+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , methodSymbol , semanticModel , cancellationToken ) ) ;
86
+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , methodSymbol . PartialImplementationPart , semanticModel , cancellationToken ) ) ;
84
87
}
85
88
else if ( member is IPropertySymbol { PartialImplementationPart : { } } propertySymbol )
86
89
{
87
- memberItems . AddIfNotNull ( CreateItemForMember ( solution , propertySymbol , tree , cancellationToken ) ) ;
88
- memberItems . AddIfNotNull ( CreateItemForMember ( solution , propertySymbol . PartialImplementationPart , tree , cancellationToken ) ) ;
90
+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , propertySymbol , semanticModel , cancellationToken ) ) ;
91
+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , propertySymbol . PartialImplementationPart , semanticModel , cancellationToken ) ) ;
89
92
}
90
93
else if ( member is IEventSymbol { PartialImplementationPart : { } } eventSymbol )
91
94
{
92
- memberItems . AddIfNotNull ( CreateItemForMember ( solution , eventSymbol , tree , cancellationToken ) ) ;
93
- memberItems . AddIfNotNull ( CreateItemForMember ( solution , eventSymbol . PartialImplementationPart , tree , cancellationToken ) ) ;
95
+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , eventSymbol , semanticModel , cancellationToken ) ) ;
96
+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , eventSymbol . PartialImplementationPart , semanticModel , cancellationToken ) ) ;
94
97
}
95
98
else if ( member is IMethodSymbol or IPropertySymbol or IEventSymbol )
96
99
{
97
100
Debug . Assert ( member is IMethodSymbol { PartialDefinitionPart : null } or IPropertySymbol { PartialDefinitionPart : null } or IEventSymbol { PartialDefinitionPart : null } ,
98
101
$ "NavBar expected GetMembers to return partial method/property/event definition parts but the implementation part was returned.") ;
99
102
100
- memberItems . AddIfNotNull ( CreateItemForMember ( solution , member , tree , cancellationToken ) ) ;
103
+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , member , semanticModel , cancellationToken ) ) ;
101
104
}
102
105
else
103
106
{
104
- memberItems . AddIfNotNull ( CreateItemForMember ( solution , member , tree , cancellationToken ) ) ;
107
+ memberItems . AddIfNotNull ( CreateItemForMember ( solution , member , semanticModel , cancellationToken ) ) ;
105
108
}
106
109
}
107
110
@@ -166,6 +169,7 @@ StatementSyntax or
166
169
{
167
170
BaseTypeDeclarationSyntax t => semanticModel . GetDeclaredSymbol ( t , cancellationToken ) ,
168
171
DelegateDeclarationSyntax d => semanticModel . GetDeclaredSymbol ( d , cancellationToken ) ,
172
+ CompilationUnitSyntax c => c . IsTopLevelProgram ( ) ? semanticModel . GetDeclaredSymbol ( c , cancellationToken ) ? . ContainingType : null ,
169
173
_ => null ,
170
174
} ;
171
175
@@ -182,18 +186,67 @@ private static bool IsAccessor(ISymbol member)
182
186
}
183
187
184
188
private static SymbolItem ? CreateItemForMember (
185
- Solution solution , ISymbol member , SyntaxTree tree , CancellationToken cancellationToken )
189
+ Solution solution , ISymbol member , SemanticModel semanticModel , CancellationToken cancellationToken )
186
190
{
187
- var location = GetSymbolLocation ( solution , member , tree , cancellationToken ) ;
191
+ var location = GetSymbolLocation ( solution , member , semanticModel . SyntaxTree , cancellationToken ) ;
188
192
if ( location == null )
189
193
return null ;
190
194
195
+ using var _ = ArrayBuilder < RoslynNavigationBarItem > . GetInstance ( out var localFunctionItems ) ;
196
+ foreach ( var syntaxReference in member . DeclaringSyntaxReferences )
197
+ {
198
+ if ( syntaxReference . SyntaxTree != semanticModel . SyntaxTree )
199
+ {
200
+ // The reference is not in this file, no need to include in the outline view.
201
+ continue ;
202
+ }
203
+
204
+ var referenceNode = syntaxReference . GetSyntax ( cancellationToken ) ;
205
+ localFunctionItems . AddRange ( CreateLocalFunctionMembers ( solution , referenceNode , semanticModel , cancellationToken ) ) ;
206
+ }
207
+
191
208
return new SymbolItem (
192
209
member . ToDisplayString ( s_memberNameFormat ) ,
193
210
member . ToDisplayString ( s_memberDetailsFormat ) ,
194
211
member . GetGlyph ( ) ,
195
212
member . IsObsolete ( ) ,
196
- location . Value ) ;
213
+ location . Value ,
214
+ localFunctionItems . ToImmutable ( ) ) ;
215
+
216
+ static ImmutableArray < RoslynNavigationBarItem > CreateLocalFunctionMembers (
217
+ Solution solution , SyntaxNode node , SemanticModel semanticModel , CancellationToken cancellationToken )
218
+ {
219
+ // Get only the local functions that are direct descendents of this method.
220
+ var localFunctions = node . DescendantNodes ( descendIntoChildren : ( n ) =>
221
+ // Always descend from the original node even if its a local function, but do not descend further into descendent local functions.
222
+ n == node || n is not LocalFunctionStatementSyntax ) . Where ( n => n is LocalFunctionStatementSyntax ) ;
223
+ using var _ = ArrayBuilder < RoslynNavigationBarItem > . GetInstance ( out var items ) ;
224
+ foreach ( var localFunction in localFunctions )
225
+ {
226
+ var localFunctionSymbol = semanticModel . GetDeclaredSymbol ( localFunction , cancellationToken ) ;
227
+ if ( localFunctionSymbol == null )
228
+ continue ;
229
+
230
+ var location = GetSymbolLocation ( solution , localFunctionSymbol , semanticModel . SyntaxTree , cancellationToken ) ;
231
+ if ( location == null )
232
+ continue ;
233
+
234
+ // Check the child local functions to see if they have nested local functions.
235
+ var childItems = CreateLocalFunctionMembers ( solution , localFunction , semanticModel , cancellationToken ) ;
236
+
237
+ var symbolItem = new SymbolItem (
238
+ localFunctionSymbol . ToDisplayString ( s_memberNameFormat ) ,
239
+ localFunctionSymbol . ToDisplayString ( s_memberDetailsFormat ) ,
240
+ localFunctionSymbol . GetGlyph ( ) ,
241
+ localFunctionSymbol . IsObsolete ( ) ,
242
+ location . Value ,
243
+ childItems ) ;
244
+
245
+ items . Add ( symbolItem ) ;
246
+ }
247
+
248
+ return items . ToImmutable ( ) ;
249
+ }
197
250
}
198
251
199
252
private static SymbolItemLocation ? GetSymbolLocation (
0 commit comments