From 98a6347bc9671b3464300a35e2156bf7dfce477b Mon Sep 17 00:00:00 2001 From: Kieron Lanning Date: Fri, 4 Sep 2026 00:37:41 +0100 Subject: [PATCH] fix: method scope failed on single param --- package.json | 2 +- src/src/SourceGeneratorShared/CodeWriter.cs | 12 +- .../CodeWriterTests.cs | 140 ++++++++++++++++++ 3 files changed, 150 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index e386169..0a2b08a 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { "name": "purview-sourcegeneratorframework", - "version": "1.0.0-prerelease.31", + "version": "1.0.0-prerelease.32", "private": true } diff --git a/src/src/SourceGeneratorShared/CodeWriter.cs b/src/src/SourceGeneratorShared/CodeWriter.cs index 26e9252..691b2d1 100644 --- a/src/src/SourceGeneratorShared/CodeWriter.cs +++ b/src/src/SourceGeneratorShared/CodeWriter.cs @@ -632,7 +632,7 @@ public CodeWriter WritePartialMethod(MethodDeclarationOptions declaration) } /// - /// Writes a structured partial method declaration. + /// Writes an expression-bodied method. /// /// writer.WriteMethodExpression(new MethodDeclarationOptions("Count", "int") { ExpressionBody = "items.Count" }); public CodeWriter WriteMethodExpression(MethodDeclarationOptions declaration) @@ -645,8 +645,12 @@ public CodeWriter WriteMethodExpression(MethodDeclarationOptions declaration) ); } - // The method is not abstract, so we can use the WriteMethod overload that takes a body callback. - return WriteMethod(declaration, _ => { }); + using (WriteMethodScope(declaration)) + { + // + } + + return this; } /// @@ -3606,6 +3610,8 @@ static void ValidateMethodDeclaration(MethodDeclarationOptions declaration) throw new ArgumentException("A readonly method cannot also be static.", nameof(declaration)); if (declaration.IsAbstract && declaration.ExpressionBody is not null) throw new ArgumentException("An abstract method cannot have an expression body.", nameof(declaration)); + if (declaration.IsPartial && declaration.ExpressionBody is not null) + throw new ArgumentException("A partial method cannot have an expression body.", nameof(declaration)); } static void ValidateOperatorDeclaration(OperatorDeclarationOptions declaration) diff --git a/src/tests/SourceGeneratorShared.UnitTests/CodeWriterTests.cs b/src/tests/SourceGeneratorShared.UnitTests/CodeWriterTests.cs index 1d90a12..749b3ed 100644 --- a/src/tests/SourceGeneratorShared.UnitTests/CodeWriterTests.cs +++ b/src/tests/SourceGeneratorShared.UnitTests/CodeWriterTests.cs @@ -980,6 +980,146 @@ await Assert ); } + [Test] + public async Task WriteMethodExpression_GivenExpressionBody_WritesExpressionBodiedMethod() + { + // Arrange + var writer = CodeWriterFactory.ForTests(); + var declaration = new MethodDeclarationOptions("Count", Type("int")) { ExpressionBody = "items.Count" }; + + // Act + writer.WriteMethodExpression(declaration); + + // Assert + await Assert.That(writer).Generates(GeneratedAttributes() + "int Count() => items.Count;\n"); + } + + [Test] + [Arguments(null)] + [Arguments("")] + [Arguments(" ")] + public async Task WriteMethodExpression_GivenWhitespaceExpressionBody_ThrowsWithoutWriting(string? expressionBody) + { + // Arrange + var writer = CodeWriterFactory.ForTests(); + var declaration = new MethodDeclarationOptions("Count", Type("int")) { ExpressionBody = expressionBody }; + + // Act / Assert + await Assert.That(() => writer.WriteMethodExpression(declaration)).Throws(); + await Assert.That(writer.ToString()).IsEmpty(); + } + + [Test] + public async Task WriteMethodExpression_GivenCallback_WritesExpressionBodiedMethod() + { + // Arrange + var writer = CodeWriterFactory.ForTests(); + var declaration = new MethodDeclarationOptions("Count", Type("int")); + + // Act + writer.WriteMethodExpression(declaration, expression => expression.Write("items.Count")); + + // Assert + await Assert.That(writer).Generates(GeneratedAttributes() + "int Count() => items.Count;\n"); + } + + [Test] + public async Task WriteMethodExpression_GivenNullCallback_Throws() + { + // Arrange + var writer = CodeWriterFactory.ForTests(); + var declaration = new MethodDeclarationOptions("Count", Type("int")); + + // Act / Assert + await Assert.That(() => writer.WriteMethodExpression(declaration, null!)).Throws(); + } + + [Test] + public async Task WriteMethodExpression_GivenExpressionBodyAndCallback_ThrowsWithoutWriting() + { + // Arrange + var writer = CodeWriterFactory.ForTests(); + var declaration = new MethodDeclarationOptions("Count", Type("int")) { ExpressionBody = "items.Count" }; + + // Act / Assert + await Assert + .That(() => writer.WriteMethodExpression(declaration, expression => expression.Write("items.Count"))) + .Throws(); + await Assert.That(writer.ToString()).IsEmpty(); + } + + [Test] + public async Task WriteMethodExpression_GivenPartialDeclaration_ThrowsWithoutWriting() + { + // Arrange + var writer = CodeWriterFactory.ForTests(); + var declaration = new MethodDeclarationOptions("Count", Type("int")) + { + IsPartial = true, + ExpressionBody = "items.Count", + }; + + // Act / Assert + await Assert.That(() => writer.WriteMethodExpression(declaration)).Throws(); + await Assert.That(writer.ToString()).IsEmpty(); + } + + [Test] + public async Task WriteMethodExpression_GivenPartialDeclarationAndCallback_ThrowsWithoutWriting() + { + // Arrange + var writer = CodeWriterFactory.ForTests(); + var declaration = new MethodDeclarationOptions("Count", Type("int")) { IsPartial = true }; + + // Act / Assert + await Assert + .That(() => writer.WriteMethodExpression(declaration, expression => expression.Write("items.Count"))) + .Throws(); + await Assert.That(writer.ToString()).IsEmpty(); + } + + [Test] + public async Task WritePartialMethod_GivenExpressionBody_ThrowsWithoutWriting() + { + // Arrange + var writer = CodeWriterFactory.ForTests(); + var declaration = new MethodDeclarationOptions("Count", Type("int")) { ExpressionBody = "items.Count" }; + + // Act / Assert + await Assert.That(() => writer.WritePartialMethod(declaration)).Throws(); + await Assert.That(writer.ToString()).IsEmpty(); + } + + [Test] + public async Task WriteMethod_GivenExpressionBody_ThrowsWithoutWriting() + { + // Arrange + var writer = CodeWriterFactory.ForTests(); + var declaration = new MethodDeclarationOptions("Count", Type("int")) { ExpressionBody = "items.Count" }; + + // Act / Assert + await Assert + .That(() => writer.WriteMethod(declaration, body => body.WriteLine("return items.Count;"))) + .Throws(); + await Assert.That(writer.ToString()).IsEmpty(); + } + + [Test] + public async Task WriteMethod_GivenBodyAndNoExpressionBody_WritesBlockBody() + { + // Arrange + var writer = CodeWriterFactory.ForTests(); + var declaration = new MethodDeclarationOptions("Count", Type("int")); + + // Act + writer.WriteMethod(declaration, body => body.WriteLine("return items.Count;")); + + // Assert + await Assert + .That(writer) + .Generates(GeneratedAttributes() + "int Count()\n" + "{\n" + "\treturn items.Count;\n" + "}\n"); + } + [Test] public async Task WritePartialMethod_GivenPartialMethods_WritesDeclaration() {