1+ using System ;
2+ using System . Collections . Generic ;
13using System . Diagnostics . CodeAnalysis ;
24using System . IO ;
35using System . Linq ;
@@ -10,8 +12,16 @@ namespace Semmle.Extraction.CSharp.Entities
1012{
1113 internal class Constructor : Method
1214 {
15+ private readonly Lazy < List < SyntaxNode > > DeclaringReferenceSyntax ;
16+
1317 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+ }
1525
1626 public override void Populate ( TextWriter trapFile )
1727 {
@@ -33,16 +43,17 @@ public override void Populate(TextWriter trapFile)
3343 protected override void ExtractInitializers ( TextWriter trapFile )
3444 {
3545 // 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+ {
3750 return ;
51+ }
3852
39- var syntax = Syntax ;
40- var initializer = syntax ? . Initializer ;
41-
42- if ( initializer is not null )
53+ if ( OrdinaryConstructorSyntax ? . Initializer is ConstructorInitializerSyntax initializer )
4354 {
4455 ITypeSymbol initializerType ;
45- var symbolInfo = Context . GetSymbolInfo ( initializer ) ;
56+ var initializerInfo = Context . GetSymbolInfo ( initializer ) ;
4657
4758 switch ( initializer . Kind ( ) )
4859 {
@@ -57,27 +68,14 @@ protected override void ExtractInitializers(TextWriter trapFile)
5768 return ;
5869 }
5970
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 ;
7977
80- init . PopulateArguments ( trapFile , initializer . ArgumentList , 0 ) ;
78+ ExtractSourceInitializer ( trapFile , primarySymbol ? . ContainingType , ( IMethodSymbol ? ) primarySymbol , primaryInitializer . ArgumentList , primaryInitializer . GetLocation ( ) ) ;
8179 }
8280 else if ( Symbol . MethodKind is MethodKind . Constructor )
8381 {
@@ -113,17 +111,50 @@ protected override void ExtractInitializers(TextWriter trapFile)
113111 }
114112 }
115113
116- private ConstructorDeclarationSyntax ? Syntax
114+ private void ExtractSourceInitializer ( TextWriter trapFile , ITypeSymbol ? type , IMethodSymbol ? symbol , ArgumentListSyntax arguments , Location location )
117115 {
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 )
119129 {
120- return Symbol . DeclaringSyntaxReferences
121- . Select ( r => r . GetSyntax ( ) )
122- . OfType < ConstructorDeclarationSyntax > ( )
123- . FirstOrDefault ( ) ;
130+ Context . ModelError ( Symbol , "Unable to resolve call" ) ;
131+ return ;
124132 }
133+
134+ trapFile . expr_call ( init , target ) ;
135+
136+ init . PopulateArguments ( trapFile , arguments , 0 ) ;
125137 }
126138
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+
127158 [ return : NotNullIfNotNull ( "constructor" ) ]
128159 public static new Constructor ? Create ( Context cx , IMethodSymbol ? constructor )
129160 {
@@ -158,19 +189,20 @@ public override void WriteId(EscapingTextWriter trapFile)
158189 trapFile . Write ( ";constructor" ) ;
159190 }
160191
161- private ConstructorDeclarationSyntax ? GetSyntax ( ) =>
162- Symbol . DeclaringSyntaxReferences . Select ( r => r . GetSyntax ( ) ) . OfType < ConstructorDeclarationSyntax > ( ) . FirstOrDefault ( ) ;
163-
164192 public override Microsoft . CodeAnalysis . Location ? FullLocation => ReportingLocation ;
165193
166194 public override Microsoft . CodeAnalysis . Location ? ReportingLocation
167195 {
168196 get
169197 {
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 )
172204 {
173- return syn . Identifier . GetLocation ( ) ;
205+ return PrimaryConstructorSyntax . Identifier . GetLocation ( ) ;
174206 }
175207
176208 if ( Symbol . IsImplicitlyDeclared )
0 commit comments