Skip to content

Commit

Permalink
Merge pull request #190 from SteveDunn/disallow-vos-in-non-partial-types
Browse files Browse the repository at this point in the history
Analyzer should fail build if ValueObject decorated type is not partial
  • Loading branch information
SteveDunn authored Jul 25, 2022
2 parents 39c10aa + b39c20a commit 8f3ec37
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 6 deletions.
6 changes: 6 additions & 0 deletions src/Vogen/BuildWorkItems.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ internal static class BuildWorkItems
return null;
}

if (!voTypeSyntax.Modifiers.Any(SyntaxKind.PartialKeyword))
{
context.ReportDiagnostic(DiagnosticItems.TypeShouldBePartial(voTypeSyntax.GetLocation(), voSymbolInformation.Name));
return null;
}

if (voSymbolInformation.IsAbstract)
{
context.ReportDiagnostic(DiagnosticItems.TypeCannotBeAbstract(voSymbolInformation));
Expand Down
3 changes: 2 additions & 1 deletion src/Vogen/Diagnostics/DiagnosticCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ public enum DiagnosticCode
TypeCannotBeAbstract = 17,
PrimaryConstructorProhibited = 18,
InvalidCustomizations = 19,
RecordToStringOverloadShouldBeSealed = 20
RecordToStringOverloadShouldBeSealed = 20,
TypeShouldBePartial = 21
}
8 changes: 8 additions & 0 deletions src/Vogen/Diagnostics/DiagnosticItems.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ internal static class DiagnosticItems
"Overrides of ToString on records should be sealed to differentiate it from the C# compiler-generated method. See https://github.com/SteveDunn/Vogen/wiki/Records#tostring for more information.",
"ToString overrides should be sealed on records. See https://github.com/SteveDunn/Vogen/wiki/Records#tostring for more information.");

private static readonly DiagnosticDescriptor _typeShouldBePartial = CreateDescriptor(
DiagnosticCode.TypeShouldBePartial,
"Value Objects should be declared in partial types.",
"Type {0} is decorated as a Value Object and should be in a partial type.");

private static readonly DiagnosticDescriptor _cannotHaveUserConstructors = CreateDescriptor(
DiagnosticCode.CannotHaveUserConstructors,
"Cannot have user defined constructors",
Expand Down Expand Up @@ -141,6 +146,9 @@ public static Diagnostic PrimaryConstructorProhibited(Location location, string
public static Diagnostic RecordToStringOverloadShouldBeSealed(Location location, string voClassName) =>
BuildDiagnostic(_recordToStringOverloadShouldBeSealed, voClassName, location);

public static Diagnostic TypeShouldBePartial(Location location, string voClassName) =>
BuildDiagnostic(_typeShouldBePartial, voClassName, location);

public static Diagnostic CannotHaveUserConstructors(IMethodSymbol constructor) =>
Create(_cannotHaveUserConstructors, constructor.Locations);

Expand Down
37 changes: 37 additions & 0 deletions tests/SmallTests/DiagnosticsTests/DisallowNonPartialTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Linq;
using FluentAssertions;
using FluentAssertions.Execution;
using Microsoft.CodeAnalysis;
using Vogen;
using Xunit;

namespace SmallTests.DiagnosticsTests;

public class DisallowNonPartialTests
{
[Theory]
[InlineData("abstract class")]
[InlineData("abstract record class")]
public void Disallows_non_partial_types(string type)
{
var source = $@"using Vogen;
namespace Whatever;
[ValueObject]
public {type} CustomerId {{ }}
";

var (diagnostics, _) = TestHelper.GetGeneratedOutput<ValueObjectGenerator>(source);

using (new AssertionScope())
{
diagnostics.Should().HaveCount(1);
Diagnostic diagnostic = diagnostics.Single();

diagnostic.Id.Should().Be("VOG021");
diagnostic.ToString().Should()
.Match("*: error VOG021: Type CustomerId is decorated as a Value Object and should be in a partial type.");
}
}
}
8 changes: 3 additions & 5 deletions tests/Testbench/Program.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
using System;
using System.Text.RegularExpressions;
using Vogen;
using Vogen;

namespace Whatever
{
public class Program
{
public static void Main()
{
Console.WriteLine(AccountId.From("xyz").ToString());
//Console.WriteLine(AccountId.From("xyz").ToString());
// To debug the source generator or analyzer, set the active project to Vogen,
// and then select Roslyn as the debug target. This requires the Roslyn SDK
// to be installed in the list of Visual Studio components.
}
}

[ValueObject(typeof(string))]
public partial record AccountId
public partial class AccountId
{
public override sealed string ToString() => "derived2!";
}
Expand Down

0 comments on commit 8f3ec37

Please sign in to comment.