Skip to content

Commit 25b9bc3

Browse files
authored
Merge pull request #1257 from aws/normj/annotations-void-fix
Fix issue with Source generator for Lambda functions that return void
2 parents 6976d22 + 454cf93 commit 25b9bc3

File tree

11 files changed

+263
-49
lines changed

11 files changed

+263
-49
lines changed

Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaMethodModel.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,14 @@ public class LambdaMethodModel
1818
public bool IsAsync { get; set; }
1919

2020
/// <summary>
21-
/// Returns true if original method returns void or <see cref="System.Threading.Tasks.Task"/>
21+
/// Returns true if original method returns void
2222
/// </summary>
23-
public bool ReturnsVoidOrTask { get; set; }
23+
public bool ReturnsVoid { get; set; }
24+
25+
/// <summary>
26+
/// Returns true if original method returns <see cref="System.Threading.Tasks.Task"/>
27+
/// </summary>
28+
public bool ReturnsTask { get; set; }
2429

2530
/// <summary>
2631
/// Gets or sets the return type of the method.

Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaMethodModelBuilder.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ public static LambdaMethodModel Build(IMethodSymbol lambdaMethodSymbol,
1818
{
1919
IsAsync = lambdaMethodSymbol.IsAsync,
2020
ReturnType = TypeModelBuilder.Build(lambdaMethodSymbol.ReturnType, context),
21-
ReturnsVoidOrTask = lambdaMethodSymbol.ReturnsVoid || lambdaMethodSymbol.ReturnType.Equals(context.Compilation.GetTypeByMetadataName("System.Threading.Tasks.Task"), SymbolEqualityComparer.Default),
21+
ReturnsVoid = lambdaMethodSymbol.ReturnsVoid,
22+
ReturnsTask = lambdaMethodSymbol.ReturnType.Equals(context.Compilation.GetTypeByMetadataName("System.Threading.Tasks.Task"), SymbolEqualityComparer.Default),
2223
Parameters = ParameterModelBuilder.Build(lambdaMethodSymbol, context),
2324
Name = lambdaMethodSymbol.Name,
2425
ContainingAssembly = lambdaMethodSymbol.ContainingAssembly.Name,

Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/LambdaFunctionTemplate.cs

Lines changed: 91 additions & 39 deletions
Large diffs are not rendered by default.

Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/LambdaFunctionTemplate.tt

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -368,10 +368,16 @@ namespace <#= _model.LambdaMethod.ContainingNamespace #>
368368
<#
369369
}
370370

371-
if (_model.LambdaMethod.ReturnsVoidOrTask)
371+
if (_model.LambdaMethod.ReturnsVoid)
372372
{
373373
#>
374-
<#= _model.LambdaMethod.IsAsync ? "await " : "" #><#= _model.LambdaMethod.ContainingType.Name.ToCamelCase() #>.<#= _model.LambdaMethod.Name #>(<#= parameters #>);
374+
<#= _model.LambdaMethod.ContainingType.Name.ToCamelCase() #>.<#= _model.LambdaMethod.Name #>(<#= parameters #>);
375+
<#
376+
}
377+
else if (_model.LambdaMethod.ReturnsTask)
378+
{
379+
#>
380+
await <#= _model.LambdaMethod.ContainingType.Name.ToCamelCase() #>.<#= _model.LambdaMethod.Name #>(<#= parameters #>);
375381
<#
376382
}
377383
else
@@ -389,7 +395,7 @@ namespace <#= _model.LambdaMethod.ContainingNamespace #>
389395
}
390396
else
391397
{
392-
if (!_model.LambdaMethod.ReturnsVoidOrTask)
398+
if (!_model.LambdaMethod.ReturnsVoid && !_model.LambdaMethod.ReturnsTask)
393399
{
394400
if (_model.LambdaMethod.ReturnType.IsValueType)
395401
{
@@ -415,7 +421,7 @@ namespace <#= _model.LambdaMethod.ContainingNamespace #>
415421
return new <#= _model.LambdaMethod.IsAsync ? _model.GeneratedMethod.ReturnType.TaskTypeArgument : _model.GeneratedMethod.ReturnType.FullName #>
416422
{
417423
<#
418-
if (!_model.LambdaMethod.ReturnsVoidOrTask)
424+
if (!_model.LambdaMethod.ReturnsVoid && !_model.LambdaMethod.ReturnsTask)
419425
{
420426
#>
421427
Body = <#= _model.LambdaMethod.ReturnType.IsString() ? "response" : "body" #>,
@@ -455,10 +461,16 @@ namespace <#= _model.LambdaMethod.ContainingNamespace #>
455461
}
456462
}
457463

458-
if (_model.LambdaMethod.ReturnsVoidOrTask)
464+
if (_model.LambdaMethod.ReturnsVoid)
459465
{
460466
#>
461-
return <#= _model.LambdaMethod.IsAsync ? "await " : "" #><#= _model.LambdaMethod.ContainingType.Name.ToCamelCase() #>.<#= _model.LambdaMethod.Name #>(<#= parameters #>);
467+
<#= _model.LambdaMethod.ContainingType.Name.ToCamelCase() #>.<#= _model.LambdaMethod.Name #>(<#= parameters #>);
468+
<#
469+
}
470+
else if (_model.LambdaMethod.ReturnsTask)
471+
{
472+
#>
473+
return await <#= _model.LambdaMethod.ContainingType.Name.ToCamelCase() #>.<#= _model.LambdaMethod.Name #>(<#= parameters #>);
462474
<#
463475
}
464476
else

Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Amazon.Lambda.Annotations.SourceGenerators.Tests.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353

5454
<ItemGroup>
5555
<None Remove="Snapshots\ServerlessTemplates\subnamespace.template" />
56+
<None Remove="Snapshots\ServerlessTemplates\voidexample.template" />
5657
</ItemGroup>
5758

5859
<ItemGroup>
@@ -73,5 +74,11 @@
7374
<ProjectReference Include="..\..\src\Amazon.Lambda.Serialization.SystemTextJson\Amazon.Lambda.Serialization.SystemTextJson.csproj" />
7475
</ItemGroup>
7576

77+
<ItemGroup>
78+
<Content Update="Snapshots\VoidExample_VoidReturn_Generated.g.cs">
79+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
80+
</Content>
81+
</ItemGroup>
82+
7683

7784
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"AWSTemplateFormatVersion": "2010-09-09",
3+
"Transform": "AWS::Serverless-2016-10-31",
4+
"Resources": {
5+
"TestServerlessAppVoidExampleVoidReturnGenerated": {
6+
"Type": "AWS::Serverless::Function",
7+
"Metadata": {
8+
"Tool": "Amazon.Lambda.Annotations"
9+
},
10+
"Properties": {
11+
"MemorySize": 256,
12+
"Timeout": 30,
13+
"Policies": [
14+
"AWSLambdaBasicExecutionRole"
15+
],
16+
"PackageType": "Image",
17+
"ImageUri": ".",
18+
"ImageConfig": {
19+
"Command": [
20+
"TestProject::TestServerlessApp.VoidExample_VoidReturn_Generated::VoidReturn"
21+
]
22+
}
23+
}
24+
}
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Linq;
3+
using System.Collections.Generic;
4+
using System.Text;
5+
using Amazon.Lambda.Core;
6+
7+
namespace TestServerlessApp
8+
{
9+
public class VoidExample_VoidReturn_Generated
10+
{
11+
private readonly VoidExample voidExample;
12+
13+
public VoidExample_VoidReturn_Generated()
14+
{
15+
SetExecutionEnvironment();
16+
voidExample = new VoidExample();
17+
}
18+
19+
public void VoidReturn(string text, Amazon.Lambda.Core.ILambdaContext __context__)
20+
{
21+
voidExample.VoidReturn(text, __context__);
22+
}
23+
24+
private static void SetExecutionEnvironment()
25+
{
26+
const string envName = "AWS_EXECUTION_ENV";
27+
28+
var envValue = new StringBuilder();
29+
30+
// If there is an existing execution environment variable add the annotations package as a suffix.
31+
if(!string.IsNullOrEmpty(Environment.GetEnvironmentVariable(envName)))
32+
{
33+
envValue.Append($"{Environment.GetEnvironmentVariable(envName)}_");
34+
}
35+
36+
envValue.Append("amazon-lambda-annotations_0.5.1.0");
37+
38+
Environment.SetEnvironmentVariable(envName, envValue.ToString());
39+
}
40+
}
41+
}

Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/SourceGeneratorTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,5 +216,41 @@ public async Task VerifyFunctionInSubNamespace()
216216
var actualTemplateContent = File.ReadAllText(Path.Combine("TestServerlessApp", "serverless.template"));
217217
Assert.Equal(expectedTemplateContent, actualTemplateContent);
218218
}
219+
220+
[Fact]
221+
public async Task VerifyFunctionReturnVoid()
222+
{
223+
var expectedTemplateContent = File.ReadAllText(Path.Combine("Snapshots", "ServerlessTemplates", "voidexample.template")).ToEnvironmentLineEndings();
224+
var expectedSubNamespaceGenerated = File.ReadAllText(Path.Combine("Snapshots", "VoidExample_VoidReturn_Generated.g.cs")).ToEnvironmentLineEndings();
225+
226+
await new VerifyCS.Test
227+
{
228+
TestState =
229+
{
230+
Sources =
231+
{
232+
(Path.Combine("TestServerlessApp", "VoidExample.cs"), File.ReadAllText(Path.Combine("TestServerlessApp", "VoidExample.cs"))),
233+
(Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"))),
234+
(Path.Combine("Amazon.Lambda.Annotations", "LambdaStartupAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "LambdaStartupAttribute.cs"))),
235+
},
236+
GeneratedSources =
237+
{
238+
(
239+
typeof(SourceGenerator.Generator),
240+
"VoidExample_VoidReturn_Generated.g.cs",
241+
SourceText.From(expectedSubNamespaceGenerated, Encoding.UTF8, SourceHashAlgorithm.Sha256)
242+
)
243+
},
244+
ExpectedDiagnostics =
245+
{
246+
new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments("VoidExample_VoidReturn_Generated.g.cs", expectedSubNamespaceGenerated),
247+
new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments($"TestServerlessApp{Path.DirectorySeparatorChar}serverless.template", expectedTemplateContent)
248+
}
249+
}
250+
}.RunAsync();
251+
252+
var actualTemplateContent = File.ReadAllText(Path.Combine("TestServerlessApp", "serverless.template"));
253+
Assert.Equal(expectedTemplateContent, actualTemplateContent);
254+
}
219255
}
220256
}

Libraries/test/TestServerlessApp.IntegrationTests/IntegrationTestContextFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public async Task InitializeAsync()
5555

5656
Assert.Equal(StackStatus.CREATE_COMPLETE, await _cloudFormationHelper.GetStackStatusAsync(_stackName));
5757
Assert.True(await _s3Helper.BucketExistsAsync(_bucketName));
58-
Assert.Equal(12, LambdaFunctions.Count);
58+
Assert.Equal(13, LambdaFunctions.Count);
5959
Assert.False(string.IsNullOrEmpty(RestApiUrlPrefix));
6060
Assert.False(string.IsNullOrEmpty(RestApiUrlPrefix));
6161

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Amazon.Lambda.Annotations;
2+
using Amazon.Lambda.Core;
3+
4+
namespace TestServerlessApp
5+
{
6+
public class VoidExample
7+
{
8+
[LambdaFunction(PackageType = LambdaPackageType.Image)]
9+
public void VoidReturn(string text, ILambdaContext context)
10+
{
11+
context.Logger.LogLine(text);
12+
}
13+
}
14+
}

Libraries/test/TestServerlessApp/serverless.template

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,26 @@
367367
]
368368
}
369369
}
370+
},
371+
"TestServerlessAppVoidExampleVoidReturnGenerated": {
372+
"Type": "AWS::Serverless::Function",
373+
"Metadata": {
374+
"Tool": "Amazon.Lambda.Annotations"
375+
},
376+
"Properties": {
377+
"MemorySize": 256,
378+
"Timeout": 30,
379+
"Policies": [
380+
"AWSLambdaBasicExecutionRole"
381+
],
382+
"PackageType": "Image",
383+
"ImageUri": ".",
384+
"ImageConfig": {
385+
"Command": [
386+
"TestServerlessApp::TestServerlessApp.VoidExample_VoidReturn_Generated::VoidReturn"
387+
]
388+
}
389+
}
370390
}
371391
},
372392
"Outputs": {

0 commit comments

Comments
 (0)