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 List < SyntaxNode > declaringReferenceSyntax ;
16
+
13
17
private Constructor ( Context cx , IMethodSymbol init )
14
- : base ( cx , init ) { }
18
+ : base ( cx , init )
19
+ {
20
+ declaringReferenceSyntax =
21
+ Symbol . DeclaringSyntaxReferences
22
+ . Select ( r => r . GetSyntax ( ) )
23
+ . ToList ( ) ;
24
+ }
15
25
16
26
public override void Populate ( TextWriter trapFile )
17
27
{
@@ -22,6 +32,12 @@ public override void Populate(TextWriter trapFile)
22
32
trapFile . constructors ( this , Symbol . ContainingType . Name , ContainingType , ( Constructor ) OriginalDefinition ) ;
23
33
trapFile . constructor_location ( this , Location ) ;
24
34
35
+ if ( IsPrimary )
36
+ {
37
+ // Create a synthetic empty body for primary constructors.
38
+ Statements . SyntheticEmptyBlock . Create ( Context , this , 0 , Location ) ;
39
+ }
40
+
25
41
if ( Symbol . IsImplicitlyDeclared )
26
42
{
27
43
var lineCounts = new LineCounts ( ) { Total = 2 , Code = 1 , Comment = 0 } ;
@@ -33,68 +49,79 @@ public override void Populate(TextWriter trapFile)
33
49
protected override void ExtractInitializers ( TextWriter trapFile )
34
50
{
35
51
// Do not extract initializers for constructed types.
36
- if ( ! IsSourceDeclaration )
52
+ // Only extract initializers for constructors with a body and primary constructors.
53
+ if ( Block is null && ExpressionBody is null && ! IsPrimary ||
54
+ ! IsSourceDeclaration )
55
+ {
37
56
return ;
57
+ }
38
58
39
- var syntax = Syntax ;
40
- var initializer = syntax ? . Initializer ;
41
-
42
- if ( initializer is null )
59
+ if ( OrdinaryConstructorSyntax ? . Initializer is ConstructorInitializerSyntax initializer )
43
60
{
44
- if ( Symbol . MethodKind is MethodKind . Constructor )
61
+ ITypeSymbol initializerType ;
62
+ var initializerInfo = Context . GetSymbolInfo ( initializer ) ;
63
+
64
+ switch ( initializer . Kind ( ) )
45
65
{
46
- var baseType = Symbol . ContainingType . BaseType ;
47
- if ( baseType is null )
48
- {
49
- if ( Symbol . ContainingType . SpecialType != SpecialType . System_Object )
50
- {
51
- Context . ModelError ( Symbol , "Unable to resolve base type in implicit constructor initializer" ) ;
52
- }
66
+ case SyntaxKind . BaseConstructorInitializer :
67
+ initializerType = Symbol . ContainingType . BaseType ! ;
68
+ break ;
69
+ case SyntaxKind . ThisConstructorInitializer :
70
+ initializerType = Symbol . ContainingType ;
71
+ break ;
72
+ default :
73
+ Context . ModelError ( initializer , "Unknown initializer" ) ;
53
74
return ;
54
- }
75
+ }
55
76
56
- var baseConstructor = baseType . InstanceConstructors . FirstOrDefault ( c => c . Arity is 0 ) ;
77
+ ExtractSourceInitializer ( trapFile , initializerType , ( IMethodSymbol ? ) initializerInfo . Symbol , initializer . ArgumentList , initializer . ThisOrBaseKeyword . GetLocation ( ) ) ;
78
+ }
79
+ else if ( PrimaryBase is PrimaryConstructorBaseTypeSyntax primaryInitializer )
80
+ {
81
+ var primaryInfo = Context . GetSymbolInfo ( primaryInitializer ) ;
82
+ var primarySymbol = primaryInfo . Symbol ;
57
83
58
- if ( baseConstructor is null )
84
+ ExtractSourceInitializer ( trapFile , primarySymbol ? . ContainingType , ( IMethodSymbol ? ) primarySymbol , primaryInitializer . ArgumentList , primaryInitializer . GetLocation ( ) ) ;
85
+ }
86
+ else if ( Symbol . MethodKind is MethodKind . Constructor )
87
+ {
88
+ var baseType = Symbol . ContainingType . BaseType ;
89
+ if ( baseType is null )
90
+ {
91
+ if ( Symbol . ContainingType . SpecialType != SpecialType . System_Object )
59
92
{
60
- Context . ModelError ( Symbol , "Unable to resolve implicit constructor initializer call" ) ;
61
- return ;
93
+ Context . ModelError ( Symbol , "Unable to resolve base type in implicit constructor initializer" ) ;
62
94
}
63
-
64
- var baseConstructorTarget = Create ( Context , baseConstructor ) ;
65
- var info = new ExpressionInfo ( Context ,
66
- AnnotatedTypeSymbol . CreateNotAnnotated ( baseType ) ,
67
- Location ,
68
- Kinds . ExprKind . CONSTRUCTOR_INIT ,
69
- this ,
70
- - 1 ,
71
- isCompilerGenerated : true ,
72
- null ) ;
73
-
74
- trapFile . expr_call ( new Expression ( info ) , baseConstructorTarget ) ;
95
+ return ;
75
96
}
76
- return ;
77
- }
78
97
79
- ITypeSymbol initializerType ;
80
- var symbolInfo = Context . GetSymbolInfo ( initializer ) ;
98
+ var baseConstructor = baseType . InstanceConstructors . FirstOrDefault ( c => c . Arity is 0 ) ;
81
99
82
- switch ( initializer . Kind ( ) )
83
- {
84
- case SyntaxKind . BaseConstructorInitializer :
85
- initializerType = Symbol . ContainingType . BaseType ! ;
86
- break ;
87
- case SyntaxKind . ThisConstructorInitializer :
88
- initializerType = Symbol . ContainingType ;
89
- break ;
90
- default :
91
- Context . ModelError ( initializer , "Unknown initializer" ) ;
100
+ if ( baseConstructor is null )
101
+ {
102
+ Context . ModelError ( Symbol , "Unable to resolve implicit constructor initializer call" ) ;
92
103
return ;
104
+ }
105
+
106
+ var baseConstructorTarget = Create ( Context , baseConstructor ) ;
107
+ var info = new ExpressionInfo ( Context ,
108
+ AnnotatedTypeSymbol . CreateNotAnnotated ( baseType ) ,
109
+ Location ,
110
+ Kinds . ExprKind . CONSTRUCTOR_INIT ,
111
+ this ,
112
+ - 1 ,
113
+ isCompilerGenerated : true ,
114
+ null ) ;
115
+
116
+ trapFile . expr_call ( new Expression ( info ) , baseConstructorTarget ) ;
93
117
}
118
+ }
94
119
120
+ private void ExtractSourceInitializer ( TextWriter trapFile , ITypeSymbol ? type , IMethodSymbol ? symbol , ArgumentListSyntax arguments , Location location )
121
+ {
95
122
var initInfo = new ExpressionInfo ( Context ,
96
- AnnotatedTypeSymbol . CreateNotAnnotated ( initializerType ) ,
97
- Context . CreateLocation ( initializer . ThisOrBaseKeyword . GetLocation ( ) ) ,
123
+ AnnotatedTypeSymbol . CreateNotAnnotated ( type ) ,
124
+ Context . CreateLocation ( location ) ,
98
125
Kinds . ExprKind . CONSTRUCTOR_INIT ,
99
126
this ,
100
127
- 1 ,
@@ -103,7 +130,7 @@ protected override void ExtractInitializers(TextWriter trapFile)
103
130
104
131
var init = new Expression ( initInfo ) ;
105
132
106
- var target = Constructor . Create ( Context , ( IMethodSymbol ? ) symbolInfo . Symbol ) ;
133
+ var target = Constructor . Create ( Context , symbol ) ;
107
134
if ( target is null )
108
135
{
109
136
Context . ModelError ( Symbol , "Unable to resolve call" ) ;
@@ -112,19 +139,27 @@ protected override void ExtractInitializers(TextWriter trapFile)
112
139
113
140
trapFile . expr_call ( init , target ) ;
114
141
115
- init . PopulateArguments ( trapFile , initializer . ArgumentList , 0 ) ;
142
+ init . PopulateArguments ( trapFile , arguments , 0 ) ;
116
143
}
117
144
118
- private ConstructorDeclarationSyntax ? Syntax
119
- {
120
- get
121
- {
122
- return Symbol . DeclaringSyntaxReferences
123
- . Select ( r => r . GetSyntax ( ) )
124
- . OfType < ConstructorDeclarationSyntax > ( )
125
- . FirstOrDefault ( ) ;
126
- }
127
- }
145
+ private ConstructorDeclarationSyntax ? OrdinaryConstructorSyntax =>
146
+ declaringReferenceSyntax
147
+ . OfType < ConstructorDeclarationSyntax > ( )
148
+ . FirstOrDefault ( ) ;
149
+
150
+ private TypeDeclarationSyntax ? PrimaryConstructorSyntax =>
151
+ declaringReferenceSyntax
152
+ . OfType < TypeDeclarationSyntax > ( )
153
+ . FirstOrDefault ( t => t is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax ) ;
154
+
155
+ private PrimaryConstructorBaseTypeSyntax ? PrimaryBase =>
156
+ PrimaryConstructorSyntax ?
157
+ . BaseList ?
158
+ . Types
159
+ . OfType < PrimaryConstructorBaseTypeSyntax > ( )
160
+ . FirstOrDefault ( ) ;
161
+
162
+ private bool IsPrimary => PrimaryConstructorSyntax is not null ;
128
163
129
164
[ return : NotNullIfNotNull ( nameof ( constructor ) ) ]
130
165
public static new Constructor ? Create ( Context cx , IMethodSymbol ? constructor )
@@ -160,19 +195,20 @@ public override void WriteId(EscapingTextWriter trapFile)
160
195
trapFile . Write ( ";constructor" ) ;
161
196
}
162
197
163
- private ConstructorDeclarationSyntax ? GetSyntax ( ) =>
164
- Symbol . DeclaringSyntaxReferences . Select ( r => r . GetSyntax ( ) ) . OfType < ConstructorDeclarationSyntax > ( ) . FirstOrDefault ( ) ;
165
-
166
198
public override Microsoft . CodeAnalysis . Location ? FullLocation => ReportingLocation ;
167
199
168
200
public override Microsoft . CodeAnalysis . Location ? ReportingLocation
169
201
{
170
202
get
171
203
{
172
- var syn = GetSyntax ( ) ;
173
- if ( syn is not null )
204
+ if ( OrdinaryConstructorSyntax is not null )
205
+ {
206
+ return OrdinaryConstructorSyntax . Identifier . GetLocation ( ) ;
207
+ }
208
+
209
+ if ( PrimaryConstructorSyntax is not null )
174
210
{
175
- return syn . Identifier . GetLocation ( ) ;
211
+ return PrimaryConstructorSyntax . Identifier . GetLocation ( ) ;
176
212
}
177
213
178
214
if ( Symbol . IsImplicitlyDeclared )
0 commit comments