From 05b31483adeafab4b648604d9e82b000ce193f1b Mon Sep 17 00:00:00 2001
From: Timo van Zijll Langhout <655426+Timovzl@users.noreply.github.com>
Date: Wed, 21 Jun 2023 22:20:16 +0200
Subject: [PATCH] Fixed a bug where arrays in (Wrapper)ValueObjects would trip
the generator.
---
.../NamespaceSymbolExtensions.cs | 13 ++++++++-----
.../TypeSymbolExtensions.cs | 7 ++++++-
.../ValueObjectGenerator.cs | 6 +++---
DomainModeling.Tests/ValueObjectTests.cs | 19 +++++++++++++++++++
.../WrapperValueObjectTests.cs | 12 ++++++++++++
DomainModeling/DomainModeling.csproj | 5 ++++-
6 files changed, 52 insertions(+), 10 deletions(-)
diff --git a/DomainModeling.Generator/NamespaceSymbolExtensions.cs b/DomainModeling.Generator/NamespaceSymbolExtensions.cs
index dbf7c66..8ec5969 100644
--- a/DomainModeling.Generator/NamespaceSymbolExtensions.cs
+++ b/DomainModeling.Generator/NamespaceSymbolExtensions.cs
@@ -1,4 +1,4 @@
-using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis;
namespace Architect.DomainModeling.Generator;
@@ -12,16 +12,16 @@ internal static class NamespaceSymbolExtensions
///
public static bool IsInSystemNamespace(this INamespaceSymbol namespaceSymbol)
{
- while (namespaceSymbol.ContainingNamespace is not null)
+ while (namespaceSymbol?.ContainingNamespace is not null)
namespaceSymbol = namespaceSymbol.ContainingNamespace;
- return namespaceSymbol.Name == "System";
+ return namespaceSymbol?.Name == "System";
}
///
/// Returns whether the given has the given .
///
- public static bool HasFullName(this INamespaceSymbol namespaceSymbol, string fullName)
+ public static bool HasFullName(this INamespaceSymbol? namespaceSymbol, string fullName)
{
return namespaceSymbol.HasFullName(fullName.AsSpan());
}
@@ -29,8 +29,11 @@ public static bool HasFullName(this INamespaceSymbol namespaceSymbol, string ful
///
/// Returns whether the given has the given .
///
- public static bool HasFullName(this INamespaceSymbol namespaceSymbol, ReadOnlySpan fullName)
+ public static bool HasFullName(this INamespaceSymbol? namespaceSymbol, ReadOnlySpan fullName)
{
+ if (namespaceSymbol is null)
+ return false;
+
do
{
var length = namespaceSymbol.Name.Length;
diff --git a/DomainModeling.Generator/TypeSymbolExtensions.cs b/DomainModeling.Generator/TypeSymbolExtensions.cs
index 04fcca2..6b2008f 100644
--- a/DomainModeling.Generator/TypeSymbolExtensions.cs
+++ b/DomainModeling.Generator/TypeSymbolExtensions.cs
@@ -43,7 +43,7 @@ public static bool IsType(this ITypeSymbol typeSymbol, ITypeSymbol comparand)
chars = chars.Slice(0, chars.Length - freeBuffer.Length);
if (containingNamespace?.IsGlobalNamespace != false)
- chars = typeSymbol.ContainingNamespace.ToString().AsSpan();
+ chars = (typeSymbol.ContainingNamespace?.ToString() ?? "").AsSpan();
if (!typeSymbol.IsType(typeSymbol.Name.AsSpan(), chars))
return false;
@@ -333,6 +333,11 @@ public static bool IsEnumerable(this ITypeSymbol typeSymbol, out INamedTypeSymbo
if (!typeSymbol.IsOrImplementsInterface(type => type.IsType("IEnumerable", "System.Collections", generic: false), out var nonGenericEnumerableInterface))
return false;
+ if (typeSymbol.Kind == SymbolKind.ArrayType)
+ {
+ elementType = ((IArrayTypeSymbol)typeSymbol).ElementType as INamedTypeSymbol;
+ return true;
+ }
if (typeSymbol.IsOrImplementsInterface(type => type.IsType("IList", "System.Collections.Generic", generic: true), out var interf))
{
elementType = interf.TypeArguments[0] as INamedTypeSymbol;
diff --git a/DomainModeling.Generator/ValueObjectGenerator.cs b/DomainModeling.Generator/ValueObjectGenerator.cs
index f27b031..35c3eb1 100644
--- a/DomainModeling.Generator/ValueObjectGenerator.cs
+++ b/DomainModeling.Generator/ValueObjectGenerator.cs
@@ -148,7 +148,7 @@ private static bool FilterSyntaxNode(SyntaxNode node, CancellationToken cancella
{
dataMemberHashCode = tuple.Member.Name.GetStableHashCode64(dataMemberHashCode);
dataMemberHashCode = ":".GetStableHashCode64(dataMemberHashCode);
- dataMemberHashCode = tuple.Type.ContainingNamespace.ToString().GetStableHashCode64(dataMemberHashCode);
+ dataMemberHashCode = (tuple.Type.ContainingNamespace?.ToString() ?? "").GetStableHashCode64(dataMemberHashCode); // Arrays have no namespace
dataMemberHashCode = ".".GetStableHashCode64(dataMemberHashCode);
dataMemberHashCode = tuple.Type.Name.GetStableHashCode64(dataMemberHashCode);
dataMemberHashCode = "&".GetStableHashCode64(dataMemberHashCode);
@@ -288,7 +288,7 @@ public bool Equals({typeName}? other)
{(existingComponents.HasFlags(ValueObjectTypeComponents.EqualsMethod) ? " */" : "")}
///
- /// Provides type inference when comparing types that are completed source-generated. The current code's source generator does not know the appropriate namespace, because the type is being generated at the same time, thus necessitating type inference.
+ /// Provides type inference when comparing types that are entirely source-generated. The current code's source generator does not know the appropriate namespace, because the type is being generated at the same time, thus necessitating type inference.
///
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
private static bool Equals(T left, T right)
@@ -307,7 +307,7 @@ public int CompareTo({typeName}? other)
}}
///
- /// Provides type inference when comparing types that are completed source-generated. The current code's source generator does not know the appropriate namespace, because the type is being generated at the same time, thus necessitating type inference.
+ /// Provides type inference when comparing types that are entirely source-generated. The current code's source generator does not know the appropriate namespace, because the type is being generated at the same time, thus necessitating type inference.
///
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
private static int Compare(T left, T right)
diff --git a/DomainModeling.Tests/ValueObjectTests.cs b/DomainModeling.Tests/ValueObjectTests.cs
index a9d8b28..7f660f5 100644
--- a/DomainModeling.Tests/ValueObjectTests.cs
+++ b/DomainModeling.Tests/ValueObjectTests.cs
@@ -1086,6 +1086,25 @@ public ImmutableArrayValueObject(IEnumerable values)
}
}
+ ///
+ /// Should merely compile.
+ ///
+ [Obsolete("Should merely compile.", error: true)]
+ [SourceGenerated]
+ public sealed partial class ArrayValueObject : ValueObject
+ {
+ protected override StringComparison StringComparison => StringComparison.OrdinalIgnoreCase;
+
+ public string?[]? StringValues { get; }
+ public int?[] IntValues { get; }
+
+ public ArrayValueObject(string?[]? stringValues, int?[] intValues)
+ {
+ this.StringValues = stringValues;
+ this.IntValues = intValues;
+ }
+ }
+
[SourceGenerated]
public sealed partial class CustomCollectionValueObject : ValueObject
{
diff --git a/DomainModeling.Tests/WrapperValueObjectTests.cs b/DomainModeling.Tests/WrapperValueObjectTests.cs
index 877369a..5c6084a 100644
--- a/DomainModeling.Tests/WrapperValueObjectTests.cs
+++ b/DomainModeling.Tests/WrapperValueObjectTests.cs
@@ -508,6 +508,18 @@ public CustomCollection(string value)
}
}
+ [SourceGenerated]
+ [Obsolete("Should merely compile.", error: true)]
+ public sealed partial class StringArrayValue : WrapperValueObject
+ {
+ }
+
+ [SourceGenerated]
+ [Obsolete("Should merely compile.", error: true)]
+ public sealed partial class DecimalArrayValue : WrapperValueObject
+ {
+ }
+
///
/// Should merely compile.
///
diff --git a/DomainModeling/DomainModeling.csproj b/DomainModeling/DomainModeling.csproj
index 5db77ed..20ca875 100644
--- a/DomainModeling/DomainModeling.csproj
+++ b/DomainModeling/DomainModeling.csproj
@@ -13,7 +13,7 @@
- 2.0.0
+ 2.0.1
A complete Domain-Driven Design (DDD) toolset for implementing domain models, including base types and source generators.
@@ -21,6 +21,9 @@ https://github.com/TheArchitectDev/Architect.DomainModeling
Release notes:
+2.0.1:
+- Fixed a bug where arrays in (Wrapper)ValueObjects would trip the generator.
+
2.0.0:
- BREAKING: Generated DummyBuilders now use UTC datetimes for generated defaults and for interpreting datetime strings.
- Semi-breaking: Generated types no longer add [Serializable] attribute, since there would be no way to remove it.