1
+ using System ;
2
+ using System . Collections . Generic ;
1
3
using System . Diagnostics . CodeAnalysis ;
2
4
using System . IO ;
3
5
using System . Linq ;
@@ -10,8 +12,16 @@ namespace Semmle.Extraction.CSharp.Entities
10
12
{
11
13
internal class Constructor : Method
12
14
{
15
+ private readonly Lazy < List < SyntaxNode > > DeclaringReferenceSyntax ;
16
+
13
17
private Constructor ( Context cx , IMethodSymbol init )
14
- : base ( cx , init ) { }
18
+ : base ( cx , init )
19
+ {
20
+ DeclaringReferenceSyntax = new ( ( ) =>
21
+ Symbol . DeclaringSyntaxReferences
22
+ . Select ( r => r . GetSyntax ( ) )
23
+ . ToList ( ) ) ;
24
+ }
15
25
16
26
public override void Populate ( TextWriter trapFile )
17
27
{
@@ -33,16 +43,17 @@ public override void Populate(TextWriter trapFile)
33
43
protected override void ExtractInitializers ( TextWriter trapFile )
34
44
{
35
45
// Do not extract initializers for constructed types.
36
- if ( ! IsSourceDeclaration )
46
+ // Only extract initializers for constructors with a body and primary constructors.
47
+ if ( Block is null && ExpressionBody is null && ! IsPrimary ||
48
+ ! IsSourceDeclaration )
49
+ {
37
50
return ;
51
+ }
38
52
39
- var syntax = Syntax ;
40
- var initializer = syntax ? . Initializer ;
41
-
42
- if ( initializer is not null )
53
+ if ( OrdinaryConstructorSyntax ? . Initializer is ConstructorInitializerSyntax initializer )
43
54
{
44
55
ITypeSymbol initializerType ;
45
- var symbolInfo = Context . GetSymbolInfo ( initializer ) ;
56
+ var initializerInfo = Context . GetSymbolInfo ( initializer ) ;
46
57
47
58
switch ( initializer . Kind ( ) )
48
59
{
@@ -57,27 +68,14 @@ protected override void ExtractInitializers(TextWriter trapFile)
57
68
return ;
58
69
}
59
70
60
- var initInfo = new ExpressionInfo ( Context ,
61
- AnnotatedTypeSymbol . CreateNotAnnotated ( initializerType ) ,
62
- Context . CreateLocation ( initializer . ThisOrBaseKeyword . GetLocation ( ) ) ,
63
- Kinds . ExprKind . CONSTRUCTOR_INIT ,
64
- this ,
65
- - 1 ,
66
- false ,
67
- null ) ;
68
-
69
- var init = new Expression ( initInfo ) ;
70
-
71
- var target = Constructor . Create ( Context , ( IMethodSymbol ? ) symbolInfo . Symbol ) ;
72
- if ( target is null )
73
- {
74
- Context . ModelError ( Symbol , "Unable to resolve call" ) ;
75
- return ;
76
- }
77
-
78
- trapFile . expr_call ( init , target ) ;
71
+ ExtractSourceInitializer ( trapFile , initializerType , ( IMethodSymbol ? ) initializerInfo . Symbol , initializer . ArgumentList , initializer . ThisOrBaseKeyword . GetLocation ( ) ) ;
72
+ }
73
+ else if ( PrimaryBase is PrimaryConstructorBaseTypeSyntax primaryInitializer )
74
+ {
75
+ var primaryInfo = Context . GetSymbolInfo ( primaryInitializer ) ;
76
+ var primarySymbol = primaryInfo . Symbol ;
79
77
80
- init . PopulateArguments ( trapFile , initializer . ArgumentList , 0 ) ;
78
+ ExtractSourceInitializer ( trapFile , primarySymbol ? . ContainingType , ( IMethodSymbol ? ) primarySymbol , primaryInitializer . ArgumentList , primaryInitializer . GetLocation ( ) ) ;
81
79
}
82
80
else if ( Symbol . MethodKind is MethodKind . Constructor )
83
81
{
@@ -113,17 +111,50 @@ protected override void ExtractInitializers(TextWriter trapFile)
113
111
}
114
112
}
115
113
116
- private ConstructorDeclarationSyntax ? Syntax
114
+ private void ExtractSourceInitializer ( TextWriter trapFile , ITypeSymbol ? type , IMethodSymbol ? symbol , ArgumentListSyntax arguments , Location location )
117
115
{
118
- get
116
+ var initInfo = new ExpressionInfo ( Context ,
117
+ AnnotatedTypeSymbol . CreateNotAnnotated ( type ) ,
118
+ Context . CreateLocation ( location ) ,
119
+ Kinds . ExprKind . CONSTRUCTOR_INIT ,
120
+ this ,
121
+ - 1 ,
122
+ false ,
123
+ null ) ;
124
+
125
+ var init = new Expression ( initInfo ) ;
126
+
127
+ var target = Constructor . Create ( Context , symbol ) ;
128
+ if ( target is null )
119
129
{
120
- return Symbol . DeclaringSyntaxReferences
121
- . Select ( r => r . GetSyntax ( ) )
122
- . OfType < ConstructorDeclarationSyntax > ( )
123
- . FirstOrDefault ( ) ;
130
+ Context . ModelError ( Symbol , "Unable to resolve call" ) ;
131
+ return ;
124
132
}
133
+
134
+ trapFile . expr_call ( init , target ) ;
135
+
136
+ init . PopulateArguments ( trapFile , arguments , 0 ) ;
125
137
}
126
138
139
+ private ConstructorDeclarationSyntax ? OrdinaryConstructorSyntax =>
140
+ DeclaringReferenceSyntax . Value
141
+ . OfType < ConstructorDeclarationSyntax > ( )
142
+ . FirstOrDefault ( ) ;
143
+
144
+ private TypeDeclarationSyntax ? PrimaryConstructorSyntax =>
145
+ DeclaringReferenceSyntax . Value
146
+ . OfType < TypeDeclarationSyntax > ( )
147
+ . FirstOrDefault ( t => t is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax ) ;
148
+
149
+ private PrimaryConstructorBaseTypeSyntax ? PrimaryBase =>
150
+ PrimaryConstructorSyntax ?
151
+ . BaseList ?
152
+ . Types
153
+ . OfType < PrimaryConstructorBaseTypeSyntax > ( )
154
+ . FirstOrDefault ( ) ;
155
+
156
+ private bool IsPrimary => PrimaryConstructorSyntax is not null ;
157
+
127
158
[ return : NotNullIfNotNull ( "constructor" ) ]
128
159
public static new Constructor ? Create ( Context cx , IMethodSymbol ? constructor )
129
160
{
@@ -158,19 +189,20 @@ public override void WriteId(EscapingTextWriter trapFile)
158
189
trapFile . Write ( ";constructor" ) ;
159
190
}
160
191
161
- private ConstructorDeclarationSyntax ? GetSyntax ( ) =>
162
- Symbol . DeclaringSyntaxReferences . Select ( r => r . GetSyntax ( ) ) . OfType < ConstructorDeclarationSyntax > ( ) . FirstOrDefault ( ) ;
163
-
164
192
public override Microsoft . CodeAnalysis . Location ? FullLocation => ReportingLocation ;
165
193
166
194
public override Microsoft . CodeAnalysis . Location ? ReportingLocation
167
195
{
168
196
get
169
197
{
170
- var syn = GetSyntax ( ) ;
171
- if ( syn is not null )
198
+ if ( OrdinaryConstructorSyntax is not null )
199
+ {
200
+ return OrdinaryConstructorSyntax . Identifier . GetLocation ( ) ;
201
+ }
202
+
203
+ if ( PrimaryConstructorSyntax is not null )
172
204
{
173
- return syn . Identifier . GetLocation ( ) ;
205
+ return PrimaryConstructorSyntax . Identifier . GetLocation ( ) ;
174
206
}
175
207
176
208
if ( Symbol . IsImplicitlyDeclared )
0 commit comments