1
+ #pragma warning disable // this came from Roslyn code
2
+ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
+
4
+ using System ;
5
+ using System . Collections . Immutable ;
6
+ using System . Linq ;
7
+ using System . Threading ;
8
+ using Microsoft . CodeAnalysis ;
9
+ using Microsoft . CodeAnalysis . CSharp ;
10
+ using Microsoft . CodeAnalysis . CSharp . Syntax ;
11
+ using Microsoft . CodeAnalysis . Text ;
12
+ using Roslyn . Utilities ;
13
+
14
+ namespace ImmutableObjectGraph . Generation . Roslyn
15
+ {
16
+ internal class CSharpDeclarationComputer : DeclarationComputer
17
+ {
18
+ public static ImmutableArray < DeclarationInfo > GetDeclarationsInSpan ( SemanticModel model , TextSpan span , bool getSymbol , CancellationToken cancellationToken )
19
+ {
20
+ var builder = ImmutableArray . CreateBuilder < DeclarationInfo > ( ) ;
21
+ ComputeDeclarations ( model , model . SyntaxTree . GetRoot ( cancellationToken ) ,
22
+ ( node , level ) => ! node . Span . OverlapsWith ( span ) || InvalidLevel ( level ) ,
23
+ getSymbol , builder , null , cancellationToken ) ;
24
+ return builder . ToImmutable ( ) ;
25
+ }
26
+
27
+ public static ImmutableArray < DeclarationInfo > GetDeclarationsInNode ( SemanticModel model , SyntaxNode node , bool getSymbol , CancellationToken cancellationToken , int ? levelsToCompute = null )
28
+ {
29
+ var builder = ImmutableArray . CreateBuilder < DeclarationInfo > ( ) ;
30
+ ComputeDeclarations ( model , node , ( n , level ) => InvalidLevel ( level ) , getSymbol , builder , levelsToCompute , cancellationToken ) ;
31
+ return builder . ToImmutable ( ) ;
32
+ }
33
+
34
+ private static bool InvalidLevel ( int ? level )
35
+ {
36
+ return level . HasValue && level . Value <= 0 ;
37
+ }
38
+
39
+ private static int ? DecrementLevel ( int ? level )
40
+ {
41
+ return level . HasValue ? level - 1 : level ;
42
+ }
43
+
44
+ internal static void ComputeDeclarations (
45
+ SemanticModel model ,
46
+ SyntaxNode node ,
47
+ Func < SyntaxNode , int ? , bool > shouldSkip ,
48
+ bool getSymbol ,
49
+ ImmutableArray < DeclarationInfo > . Builder builder ,
50
+ int ? levelsToCompute ,
51
+ CancellationToken cancellationToken )
52
+ {
53
+ if ( shouldSkip ( node , levelsToCompute ) )
54
+ {
55
+ return ;
56
+ }
57
+
58
+ var newLevel = DecrementLevel ( levelsToCompute ) ;
59
+
60
+ switch ( node . Kind ( ) )
61
+ {
62
+ case SyntaxKind . NamespaceDeclaration :
63
+ {
64
+ var ns = ( NamespaceDeclarationSyntax ) node ;
65
+ foreach ( var decl in ns . Members ) ComputeDeclarations ( model , decl , shouldSkip , getSymbol , builder , newLevel , cancellationToken ) ;
66
+ builder . Add ( GetDeclarationInfo ( model , node , getSymbol , cancellationToken ) ) ;
67
+
68
+ NameSyntax name = ns . Name ;
69
+ while ( name . Kind ( ) == SyntaxKind . QualifiedName )
70
+ {
71
+ name = ( ( QualifiedNameSyntax ) name ) . Left ;
72
+ var declaredSymbol = getSymbol ? model . GetSymbolInfo ( name , cancellationToken ) . Symbol : null ;
73
+ builder . Add ( new DeclarationInfo ( name , ImmutableArray < SyntaxNode > . Empty , declaredSymbol ) ) ;
74
+ }
75
+
76
+ return ;
77
+ }
78
+
79
+ case SyntaxKind . ClassDeclaration :
80
+ case SyntaxKind . StructDeclaration :
81
+ case SyntaxKind . InterfaceDeclaration :
82
+ {
83
+ var t = ( TypeDeclarationSyntax ) node ;
84
+ foreach ( var decl in t . Members ) ComputeDeclarations ( model , decl , shouldSkip , getSymbol , builder , newLevel , cancellationToken ) ;
85
+ builder . Add ( GetDeclarationInfo ( model , node , getSymbol , cancellationToken ) ) ;
86
+ return ;
87
+ }
88
+
89
+ case SyntaxKind . EnumDeclaration :
90
+ {
91
+ var t = ( EnumDeclarationSyntax ) node ;
92
+ foreach ( var decl in t . Members ) ComputeDeclarations ( model , decl , shouldSkip , getSymbol , builder , newLevel , cancellationToken ) ;
93
+ builder . Add ( GetDeclarationInfo ( model , node , getSymbol , cancellationToken ) ) ;
94
+ return ;
95
+ }
96
+
97
+ case SyntaxKind . EnumMemberDeclaration :
98
+ {
99
+ var t = ( EnumMemberDeclarationSyntax ) node ;
100
+ builder . Add ( GetDeclarationInfo ( model , node , getSymbol , t . EqualsValue , cancellationToken ) ) ;
101
+ return ;
102
+ }
103
+
104
+ case SyntaxKind . DelegateDeclaration :
105
+ {
106
+ var t = ( DelegateDeclarationSyntax ) node ;
107
+ builder . Add ( GetDeclarationInfo ( model , node , getSymbol , cancellationToken ) ) ;
108
+ return ;
109
+ }
110
+
111
+ case SyntaxKind . EventDeclaration :
112
+ {
113
+ var t = ( EventDeclarationSyntax ) node ;
114
+ foreach ( var decl in t . AccessorList . Accessors ) ComputeDeclarations ( model , decl , shouldSkip , getSymbol , builder , newLevel , cancellationToken ) ;
115
+ builder . Add ( GetDeclarationInfo ( model , node , getSymbol , cancellationToken ) ) ;
116
+ return ;
117
+ }
118
+
119
+ case SyntaxKind . EventFieldDeclaration :
120
+ case SyntaxKind . FieldDeclaration :
121
+ {
122
+ var t = ( BaseFieldDeclarationSyntax ) node ;
123
+ foreach ( var decl in t . Declaration . Variables )
124
+ {
125
+ builder . Add ( GetDeclarationInfo ( model , decl , getSymbol , decl . Initializer , cancellationToken ) ) ;
126
+ }
127
+
128
+ return ;
129
+ }
130
+
131
+ case SyntaxKind . ArrowExpressionClause :
132
+ {
133
+ // Arrow expression clause declares getter symbol for properties and indexers.
134
+ var parentProperty = node . Parent as BasePropertyDeclarationSyntax ;
135
+ if ( parentProperty != null )
136
+ {
137
+ builder . Add ( GetExpressionBodyDeclarationInfo ( parentProperty , ( ArrowExpressionClauseSyntax ) node , model , getSymbol , cancellationToken ) ) ;
138
+ }
139
+
140
+ return ;
141
+ }
142
+
143
+ case SyntaxKind . PropertyDeclaration :
144
+ {
145
+ var t = ( PropertyDeclarationSyntax ) node ;
146
+ if ( t . AccessorList != null )
147
+ {
148
+ foreach ( var decl in t . AccessorList . Accessors ) ComputeDeclarations ( model , decl , shouldSkip , getSymbol , builder , newLevel , cancellationToken ) ;
149
+ }
150
+
151
+ if ( t . ExpressionBody != null )
152
+ {
153
+ ComputeDeclarations ( model , t . ExpressionBody , shouldSkip , getSymbol , builder , levelsToCompute , cancellationToken ) ;
154
+ }
155
+
156
+ builder . Add ( GetDeclarationInfo ( model , node , getSymbol , cancellationToken , t . Initializer ) ) ;
157
+ return ;
158
+ }
159
+
160
+ case SyntaxKind . IndexerDeclaration :
161
+ {
162
+ var t = ( IndexerDeclarationSyntax ) node ;
163
+ if ( t . AccessorList != null )
164
+ {
165
+ foreach ( var decl in t . AccessorList . Accessors )
166
+ {
167
+ ComputeDeclarations ( model , decl , shouldSkip , getSymbol , builder , newLevel , cancellationToken ) ;
168
+ }
169
+ }
170
+
171
+ if ( t . ExpressionBody != null )
172
+ {
173
+ ComputeDeclarations ( model , t . ExpressionBody , shouldSkip , getSymbol , builder , levelsToCompute , cancellationToken ) ;
174
+ }
175
+
176
+ var codeBlocks = t . ParameterList != null ? t . ParameterList . Parameters . Select ( p => p . Default ) : Enumerable . Empty < SyntaxNode > ( ) ;
177
+
178
+ builder . Add ( GetDeclarationInfo ( model , node , getSymbol , codeBlocks , cancellationToken ) ) ;
179
+ return ;
180
+ }
181
+
182
+ case SyntaxKind . AddAccessorDeclaration :
183
+ case SyntaxKind . RemoveAccessorDeclaration :
184
+ case SyntaxKind . SetAccessorDeclaration :
185
+ case SyntaxKind . GetAccessorDeclaration :
186
+ {
187
+ var t = ( AccessorDeclarationSyntax ) node ;
188
+ builder . Add ( GetDeclarationInfo ( model , node , getSymbol , t . Body , cancellationToken ) ) ;
189
+ return ;
190
+ }
191
+
192
+ case SyntaxKind . ConstructorDeclaration :
193
+ case SyntaxKind . ConversionOperatorDeclaration :
194
+ case SyntaxKind . DestructorDeclaration :
195
+ case SyntaxKind . MethodDeclaration :
196
+ case SyntaxKind . OperatorDeclaration :
197
+ {
198
+ var t = ( BaseMethodDeclarationSyntax ) node ;
199
+ var codeBlocks = t . ParameterList != null ? t . ParameterList . Parameters . Select ( p => p . Default ) : Enumerable . Empty < SyntaxNode > ( ) ;
200
+ codeBlocks = codeBlocks . Concat ( new [ ] { t . Body } ) ;
201
+
202
+ var ctorDecl = t as ConstructorDeclarationSyntax ;
203
+ if ( ctorDecl != null && ctorDecl . Initializer != null )
204
+ {
205
+ codeBlocks = codeBlocks . Concat ( new [ ] { ctorDecl . Initializer } ) ;
206
+ }
207
+
208
+ var expressionBody = GetExpressionBodySyntax ( t ) ;
209
+ if ( expressionBody != null )
210
+ {
211
+ codeBlocks = codeBlocks . Concat ( new [ ] { expressionBody } ) ;
212
+ }
213
+
214
+ builder . Add ( GetDeclarationInfo ( model , node , getSymbol , codeBlocks , cancellationToken ) ) ;
215
+ return ;
216
+ }
217
+
218
+ case SyntaxKind . CompilationUnit :
219
+ {
220
+ var t = ( CompilationUnitSyntax ) node ;
221
+ foreach ( var decl in t . Members ) ComputeDeclarations ( model , decl , shouldSkip , getSymbol , builder , newLevel , cancellationToken ) ;
222
+ return ;
223
+ }
224
+
225
+ default :
226
+ return ;
227
+ }
228
+ }
229
+
230
+ private static DeclarationInfo GetExpressionBodyDeclarationInfo (
231
+ BasePropertyDeclarationSyntax declarationWithExpressionBody ,
232
+ ArrowExpressionClauseSyntax expressionBody ,
233
+ SemanticModel model ,
234
+ bool getSymbol ,
235
+ CancellationToken cancellationToken )
236
+ {
237
+ // TODO: use 'model.GetDeclaredSymbol(expressionBody)' when compiler is fixed to return the getter symbol for it.
238
+ var declaredAccessor = getSymbol ? ( model . GetDeclaredSymbol ( declarationWithExpressionBody , cancellationToken ) as IPropertySymbol ) ? . GetMethod : null ;
239
+
240
+ return new DeclarationInfo (
241
+ declaredNode : expressionBody ,
242
+ executableCodeBlocks : ImmutableArray . Create < SyntaxNode > ( expressionBody ) ,
243
+ declaredSymbol : declaredAccessor ) ;
244
+ }
245
+
246
+ /// <summary>
247
+ /// Gets the expression-body syntax from an expression-bodied member. The
248
+ /// given syntax must be for a member which could contain an expression-body.
249
+ /// </summary>
250
+ internal static ArrowExpressionClauseSyntax GetExpressionBodySyntax ( CSharpSyntaxNode node )
251
+ {
252
+ ArrowExpressionClauseSyntax arrowExpr = null ;
253
+ switch ( node . Kind ( ) )
254
+ {
255
+ // The ArrowExpressionClause is the declaring syntax for the
256
+ // 'get' SourcePropertyAccessorSymbol of properties and indexers.
257
+ case SyntaxKind . ArrowExpressionClause :
258
+ arrowExpr = ( ArrowExpressionClauseSyntax ) node ;
259
+ break ;
260
+ case SyntaxKind . MethodDeclaration :
261
+ arrowExpr = ( ( MethodDeclarationSyntax ) node ) . ExpressionBody ;
262
+ break ;
263
+ case SyntaxKind . OperatorDeclaration :
264
+ arrowExpr = ( ( OperatorDeclarationSyntax ) node ) . ExpressionBody ;
265
+ break ;
266
+ case SyntaxKind . ConversionOperatorDeclaration :
267
+ arrowExpr = ( ( ConversionOperatorDeclarationSyntax ) node ) . ExpressionBody ;
268
+ break ;
269
+ case SyntaxKind . PropertyDeclaration :
270
+ arrowExpr = ( ( PropertyDeclarationSyntax ) node ) . ExpressionBody ;
271
+ break ;
272
+ case SyntaxKind . IndexerDeclaration :
273
+ arrowExpr = ( ( IndexerDeclarationSyntax ) node ) . ExpressionBody ;
274
+ break ;
275
+ case SyntaxKind . ConstructorDeclaration :
276
+ case SyntaxKind . DestructorDeclaration :
277
+ return null ;
278
+ default :
279
+ // Don't throw, just use for the assert in case this is used in the semantic model
280
+ ////ExceptionUtilities.UnexpectedValue(node.Kind());
281
+ break ;
282
+ }
283
+ return arrowExpr ;
284
+ }
285
+ }
286
+ }
0 commit comments