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