Skip to content

Commit 49d7474

Browse files
committed
Fixed stub generation for methods inside statement blocks
1 parent 34d693e commit 49d7474

File tree

6 files changed

+365
-63
lines changed

6 files changed

+365
-63
lines changed

SourceGenerator/Extensions/SyntaxNodeExtension.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ internal static class SyntaxNodeExtension
1616
return null;
1717
}
1818

19-
node = node?.Parent;
19+
node = node.Parent;
2020
}
2121

2222
return node as T;

SourceGenerator/Helpers/CSharpMemberGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ internal static string GetArgumentList(SeparatedSyntaxList<ArgumentSyntax> argum
8282
return string.Empty;
8383
}
8484

85-
StringBuilder argumentList = new StringBuilder();
85+
StringBuilder argumentList = new();
8686

8787
foreach (ArgumentSyntax argument in arguments)
8888
{

SourceGenerator/SourceGenerator.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<Description>Source Generator for adding missing methods and classes inside tests to allow compilation. Assists on creating code exercises.</Description>
1616
<RepositoryUrl>https://github.com/TMC-CSharp/CodeExerciseLibrary.git</RepositoryUrl>
1717
<RepositoryType>git</RepositoryType>
18-
<Version>1.2</Version>
18+
<Version>1.2.1</Version>
1919
</PropertyGroup>
2020

2121
<ItemGroup>

SourceGenerator/TestGenerator.cs

Lines changed: 139 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Collections.Immutable;
4+
using System.Diagnostics;
45
using System.Dynamic;
56
using System.IO;
67
using System.Linq;
@@ -79,53 +80,131 @@ private void ProcessSyntax(GeneratorExecutionContext context, ref Compilation co
7980
switch (syntax)
8081
{
8182
case BlockSyntax block:
82-
{
83-
foreach (StatementSyntax statementSyntax in block.Statements)
8483
{
85-
this.ProcessStatement(context, ref compilation, @namespace, @class, statementSyntax, null);
86-
}
84+
foreach (StatementSyntax statementSyntax in block.Statements)
85+
{
86+
this.ProcessSyntax(context, ref compilation, @namespace, @class, statementSyntax);
87+
}
8788

88-
break;
89-
}
89+
break;
90+
}
9091
case InvocationExpressionSyntax invocation:
9192
this.ProcessInvocation(context, ref compilation, @namespace, @class, invocation, null);
9293
break;
93-
}
94-
}
95-
96-
private void ProcessStatement(GeneratorExecutionContext context, ref Compilation compilation, NamespaceDeclarationSyntax @namespace, ClassDeclarationSyntax @class, StatementSyntax statement, TypeSyntax? returnType)
97-
{
98-
switch (statement)
99-
{
10094
case LocalDeclarationStatementSyntax declaration:
101-
{
102-
this.ProcessLocalDeclaration(context, ref compilation, @namespace, declaration);
95+
{
96+
this.ProcessLocalDeclaration(context, ref compilation, @namespace, declaration);
10397

104-
foreach (VariableDeclaratorSyntax variableDeclaration in declaration.Declaration.Variables)
98+
foreach (VariableDeclaratorSyntax variableDeclaration in declaration.Declaration.Variables)
99+
{
100+
switch (variableDeclaration.Initializer?.Value)
101+
{
102+
case InvocationExpressionSyntax invocation:
103+
this.ProcessInvocation(context, ref compilation, @namespace, @class, invocation, declaration.Declaration.Type);
104+
break;
105+
case ObjectCreationExpressionSyntax objectCreation:
106+
this.ProcessObjectCreation(context, ref compilation, @namespace, @class, objectCreation);
107+
break;
108+
case SwitchExpressionSyntax @switch:
109+
foreach (SwitchExpressionArmSyntax switchArm in @switch.Arms)
110+
{
111+
this.ProcessSyntax(context, ref compilation, @namespace, @class, switchArm.Expression);
112+
}
113+
break;
114+
}
115+
}
116+
117+
break;
118+
}
119+
case ExpressionStatementSyntax expression:
105120
{
106-
switch (variableDeclaration.Initializer?.Value)
121+
if (expression.Expression is not InvocationExpressionSyntax invocation)
107122
{
108-
case InvocationExpressionSyntax invocation:
109-
this.ProcessInvocation(context, ref compilation, @namespace, @class, invocation, declaration.Declaration.Type);
110-
break;
111-
case ObjectCreationExpressionSyntax objectCreation:
112-
this.ProcessObjectCreation(context, ref compilation, @namespace, @class, objectCreation);
113-
break;
123+
return;
114124
}
125+
126+
this.ProcessInvocation(context, ref compilation, @namespace, @class, invocation, null);
127+
break;
128+
}
129+
case UsingStatementSyntax @using:
130+
{
131+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @using.Statement);
132+
break;
115133
}
134+
case TryStatementSyntax @try:
135+
{
136+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @try.Block);
116137

117-
break;
118-
}
119-
case ExpressionStatementSyntax expression:
120-
{
121-
if (expression.Expression is not InvocationExpressionSyntax invocation)
138+
foreach (CatchClauseSyntax @catch in @try.Catches)
139+
{
140+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @catch.Block);
141+
}
142+
143+
if (@try.Finally is not null)
144+
{
145+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @try.Finally);
146+
}
147+
break;
148+
}
149+
case FinallyClauseSyntax @finally:
122150
{
123-
return;
151+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @finally.Block);
152+
break;
124153
}
154+
case ForEachStatementSyntax @foreach:
155+
{
156+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @foreach.Statement);
157+
break;
158+
}
159+
case ForStatementSyntax @for:
160+
{
161+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @for.Statement);
162+
break;
163+
}
164+
case WhileStatementSyntax @while:
165+
{
166+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @while.Statement);
167+
break;
168+
}
169+
case DoStatementSyntax @do:
170+
{
171+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @do.Statement);
172+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @do.Condition);
173+
break;
174+
}
175+
case CheckedStatementSyntax @checked:
176+
{
177+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @checked.Block);
178+
break;
179+
}
180+
case FixedStatementSyntax @fixed:
181+
{
182+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @fixed.Statement);
183+
break;
184+
}
185+
case UnsafeStatementSyntax @unsafe:
186+
{
187+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @unsafe.Block);
188+
break;
189+
}
190+
case LockStatementSyntax @lock:
191+
{
192+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @lock.Statement);
193+
break;
194+
}
195+
case SwitchStatementSyntax @switch:
196+
{
197+
this.ProcessSyntax(context, ref compilation, @namespace, @class, @switch.Expression);
125198

126-
this.ProcessInvocation(context, ref compilation, @namespace, @class, invocation, returnType);
127-
break;
128-
}
199+
foreach (SwitchSectionSyntax section in @switch.Sections)
200+
{
201+
foreach (StatementSyntax statement in section.Statements)
202+
{
203+
this.ProcessSyntax(context, ref compilation, @namespace, @class, statement);
204+
}
205+
}
206+
break;
207+
}
129208
}
130209
}
131210

@@ -259,7 +338,7 @@ private ITypeSymbol GenerateEmptyClass(GeneratorExecutionContext context, ref Co
259338

260339
static byte[] Emit(CSharpCompilation compilation)
261340
{
262-
using MemoryStream memoryStream = new MemoryStream();
341+
using MemoryStream memoryStream = new();
263342

264343
compilation.Emit(memoryStream);
265344

@@ -287,30 +366,30 @@ private void ProcessArguments(GeneratorExecutionContext context, ref Compilation
287366
switch (argument.Expression)
288367
{
289368
case InvocationExpressionSyntax argumentInvocation:
290-
{
291-
TypeSyntax argumentReturnType = SyntaxFactory.ParseTypeName("dynamic");
369+
{
370+
TypeSyntax argumentReturnType = SyntaxFactory.ParseTypeName("dynamic");
292371

293-
this.ProcessInvocation(context, ref compilation, @namespace, @class, argumentInvocation, argumentReturnType);
294-
break;
295-
}
372+
this.ProcessInvocation(context, ref compilation, @namespace, @class, argumentInvocation, argumentReturnType);
373+
break;
374+
}
296375
case MemberAccessExpressionSyntax memberAccess:
297-
{
298-
IdentifierNameSyntax targetIdentifier = memberAccess.DescendantNodes().OfType<IdentifierNameSyntax>().LastOrDefault();
299-
if (targetIdentifier is null)
300376
{
301-
continue;
302-
}
377+
IdentifierNameSyntax? targetIdentifier = memberAccess.DescendantNodes().OfType<IdentifierNameSyntax>().LastOrDefault();
378+
if (targetIdentifier is null)
379+
{
380+
continue;
381+
}
303382

304-
(bool isStatic, ITypeSymbol? extendingClass) = this.ProcessMemberAccess(context, ref compilation, @namespace, memberAccess);
305-
if (!isStatic || extendingClass is null)
306-
{
307-
continue;
308-
}
383+
(bool isStatic, ITypeSymbol? extendingClass) = this.ProcessMemberAccess(context, ref compilation, @namespace, memberAccess);
384+
if (!isStatic || extendingClass is null)
385+
{
386+
continue;
387+
}
309388

310-
this.GenerateStaticField(context, @namespace, @class, extendingClass, targetIdentifier);
389+
this.GenerateStaticField(context, @namespace, @class, extendingClass, targetIdentifier);
311390

312-
break;
313-
}
391+
break;
392+
}
314393
}
315394
}
316395
}
@@ -333,7 +412,7 @@ private void ProcessInvocation(GeneratorExecutionContext context, ref Compilatio
333412

334413
string arguments = CSharpMemberGenerator.GetArgumentList(invocation.ArgumentList.Arguments);
335414

336-
this.GenerateMethod(context, isStatic, @namespace, @class, extendingClass, memberAccess, arguments, returnType == null ? "void" : "dynamic"); //Use dynamic as quick hack for return values
415+
this.GenerateMethod(context, isStatic, @namespace, @class, extendingClass, memberAccess, arguments, "dynamic"); //Use dynamic as quick hack for return values
337416
}
338417

339418
private (bool isStatic, ITypeSymbol? symbol) ProcessMemberAccess(GeneratorExecutionContext context, ref Compilation compilation, NamespaceDeclarationSyntax @namespace, MemberAccessExpressionSyntax memberAccess)
@@ -343,7 +422,7 @@ private void ProcessInvocation(GeneratorExecutionContext context, ref Compilatio
343422
{
344423
return default;
345424
}
346-
425+
347426
IdentifierNameSyntax targetIdentifier = memberAccess.DescendantNodes().OfType<IdentifierNameSyntax>().LastOrDefault();
348427
if (targetIdentifier is null)
349428
{
@@ -409,12 +488,12 @@ private void ProcessInvocation(GeneratorExecutionContext context, ref Compilatio
409488
extendingClass = methodSymbol.ReturnType;
410489
break;
411490
default:
412-
{
413-
//Ehh... Lets assume its a missing static class? Ehheheh...
414-
ITypeSymbol symbol = this.GenerateEmptyClass(context, ref compilation, @namespace, targetIdentifier.ToString());
491+
{
492+
//Ehh... Lets assume its a missing static class? Ehheheh...
493+
ITypeSymbol symbol = this.GenerateEmptyClass(context, ref compilation, @namespace, targetIdentifier.ToString());
415494

416-
return (true, symbol);
417-
}
495+
return (true, symbol);
496+
}
418497
}
419498

420499
return (isStatic, extendingClass);
@@ -454,8 +533,8 @@ private void GenerateStaticField(GeneratorExecutionContext context, NamespaceDec
454533

455534
private class SyntaxReceiver : ISyntaxReceiver
456535
{
457-
internal List<ClassDeclarationSyntax> Classes { get; } = new List<ClassDeclarationSyntax>();
458-
internal List<LambdaExpressionSyntax> Lambda { get; } = new List<LambdaExpressionSyntax>();
536+
internal List<ClassDeclarationSyntax> Classes { get; } = new();
537+
internal List<LambdaExpressionSyntax> Lambda { get; } = new();
459538

460539
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
461540
{

0 commit comments

Comments
 (0)