diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/AttributeInfo.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/AttributeInfo.cs index 4736de1d..f8efc93d 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/AttributeInfo.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/AttributeInfo.cs @@ -74,15 +74,15 @@ private AttributeInfo( } else if (attribute.AttributeClass.IsValueObjectValidationErrorAttribute()) { - validationError = new ValidationErrorState(attribute.AttributeClass.TypeArguments[0].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); + validationError = new ValidationErrorState(attribute.AttributeClass.TypeArguments[0].ToFullyQualifiedDisplayString()); } else if (attribute.AttributeClass.IsValueObjectKeyMemberComparerAttribute()) { - keyMemberComparerAccessor = attribute.AttributeClass.TypeArguments[0].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + keyMemberComparerAccessor = attribute.AttributeClass.TypeArguments[0].ToFullyQualifiedDisplayString(); } else if (attribute.AttributeClass.IsValueObjectKeyMemberEqualityComparerAttribute()) { - keyMemberEqualityComparerAccessor = attribute.AttributeClass.TypeArguments[0].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + keyMemberEqualityComparerAccessor = attribute.AttributeClass.TypeArguments[0].ToFullyQualifiedDisplayString(); } else if (attribute.AttributeClass.IsSmartEnumAttribute() || attribute.AttributeClass.IsKeyedValueObjectAttribute() diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/CachedTypedMemberState.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/CachedTypedMemberState.cs index 4e23bb81..e492cbb5 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/CachedTypedMemberState.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/CachedTypedMemberState.cs @@ -5,9 +5,6 @@ public class CachedTypedMemberState : IEquatable, ITyped private readonly int _hashCode; public string TypeFullyQualified { get; } - public string TypeFullyQualifiedNullable { get; } - public string TypeFullyQualifiedNullAnnotated { get; } - public string TypeFullyQualifiedWithNullability { get; } public string TypeMinimallyQualified { get; } public SpecialType SpecialType { get; } public bool IsReferenceType { get; } @@ -28,9 +25,6 @@ public CachedTypedMemberState(ITypedMemberState typedMemberState) _hashCode = typedMemberState.GetHashCode(); TypeFullyQualified = typedMemberState.TypeFullyQualified; - TypeFullyQualifiedNullable = typedMemberState.TypeFullyQualifiedNullable; - TypeFullyQualifiedNullAnnotated = typedMemberState.TypeFullyQualifiedNullAnnotated; - TypeFullyQualifiedWithNullability = typedMemberState.TypeFullyQualifiedWithNullability; TypeMinimallyQualified = typedMemberState.TypeMinimallyQualified; SpecialType = typedMemberState.SpecialType; IsReferenceType = typedMemberState.IsReferenceType; diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ComparableCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ComparableCodeGenerator.cs index ccef0fb1..5155f93a 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ComparableCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ComparableCodeGenerator.cs @@ -20,7 +20,7 @@ public void GenerateBaseTypes(StringBuilder sb, InterfaceCodeGeneratorState stat { sb.Append(@" global::System.IComparable, - global::System.IComparable<").Append(state.Type.TypeFullyQualified).Append(">"); + global::System.IComparable<").AppendTypeFullyQualified(state.Type).Append(">"); } public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState state) @@ -32,14 +32,14 @@ public int CompareTo(object? obj) if(obj is null) return 1; - if(obj is not ").Append(state.Type.TypeFullyQualified).Append(@" item) + if(obj is not ").AppendTypeFullyQualified(state.Type).Append(@" item) throw new global::System.ArgumentException(""Argument must be of type \""").Append(state.Type.TypeMinimallyQualified).Append(@"\""."", nameof(obj)); return this.CompareTo(item); } /// - public int CompareTo(").Append(state.Type.TypeFullyQualifiedNullAnnotated).Append(@" obj) + public int CompareTo(").AppendTypeFullyQualifiedNullAnnotated(state.Type).Append(@" obj) {"); if (state.Type.IsReferenceType) diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ComparisonOperatorsCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ComparisonOperatorsCodeGenerator.cs index d83c2037..7ff509ab 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ComparisonOperatorsCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ComparisonOperatorsCodeGenerator.cs @@ -64,13 +64,13 @@ public void GenerateBaseTypes(StringBuilder sb, InterfaceCodeGeneratorState stat return; sb.Append(@" - global::System.Numerics.IComparisonOperators<").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.Type.TypeFullyQualified).Append(", bool>"); + global::System.Numerics.IComparisonOperators<").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.Type).Append(", bool>"); if (!_withKeyTypeOverloads) return; sb.Append(@", - global::System.Numerics.IComparisonOperators<").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.KeyMember.TypeFullyQualified).Append(", bool>"); + global::System.Numerics.IComparisonOperators<").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.KeyMember).Append(", bool>"); } public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState state) @@ -106,7 +106,7 @@ private static void GenerateUsingOperators( { sb.Append(@" /// - public static bool operator <(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator <(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(leftNullCheck).Append(rightNullCheck).Append("return left.").Append(state.KeyMember.Name).Append(" < right.").Append(state.KeyMember.Name).Append(@"; }"); @@ -117,7 +117,7 @@ private static void GenerateUsingOperators( sb.Append(@" /// - public static bool operator <=(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator <=(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(leftNullCheck).Append(rightNullCheck).Append("return left.").Append(state.KeyMember.Name).Append(" <= right.").Append(state.KeyMember.Name).Append(@"; }"); @@ -128,7 +128,7 @@ private static void GenerateUsingOperators( sb.Append(@" /// - public static bool operator >(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator >(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(leftNullCheck).Append(rightNullCheck).Append("return left.").Append(state.KeyMember.Name).Append(" > right.").Append(state.KeyMember.Name).Append(@"; }"); @@ -139,7 +139,7 @@ private static void GenerateUsingOperators( sb.Append(@" /// - public static bool operator >=(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator >=(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(leftNullCheck).Append(rightNullCheck).Append("return left.").Append(state.KeyMember.Name).Append(" >= right.").Append(state.KeyMember.Name).Append(@"; }"); @@ -156,25 +156,25 @@ private static void GenerateUsingComparerAccessor( sb.Append(@" /// - public static bool operator <(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator <(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(leftNullCheck).Append(rightNullCheck).Append("return ").Append(comparerAccessor).Append(".Comparer.Compare(left.").Append(state.KeyMember.Name).Append(", right.").Append(state.KeyMember.Name).Append(@") < 0; } /// - public static bool operator <=(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator <=(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(leftNullCheck).Append(rightNullCheck).Append("return ").Append(comparerAccessor).Append(".Comparer.Compare(left.").Append(state.KeyMember.Name).Append(", right.").Append(state.KeyMember.Name).Append(@") <= 0; } /// - public static bool operator >(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator >(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(leftNullCheck).Append(rightNullCheck).Append("return ").Append(comparerAccessor).Append(".Comparer.Compare(left.").Append(state.KeyMember.Name).Append(", right.").Append(state.KeyMember.Name).Append(@") > 0; } /// - public static bool operator >=(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator >=(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(leftNullCheck).Append(rightNullCheck).Append("return ").Append(comparerAccessor).Append(".Comparer.Compare(left.").Append(state.KeyMember.Name).Append(", right.").Append(state.KeyMember.Name).Append(@") >= 0; }"); @@ -189,25 +189,25 @@ private static void GenerateUsingOrdinalIgnoreCaseComparer( sb.Append(@" /// - public static bool operator <(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator <(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(leftNullCheck).Append(rightNullCheck).Append("return global::System.StringComparer.OrdinalIgnoreCase.Compare(left.").Append(state.KeyMember.Name).Append(", right.").Append(state.KeyMember.Name).Append(@") < 0; } /// - public static bool operator <=(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator <=(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(leftNullCheck).Append(rightNullCheck).Append("return global::System.StringComparer.OrdinalIgnoreCase.Compare(left.").Append(state.KeyMember.Name).Append(", right.").Append(state.KeyMember.Name).Append(@") <= 0; } /// - public static bool operator >(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator >(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(leftNullCheck).Append(rightNullCheck).Append("return global::System.StringComparer.OrdinalIgnoreCase.Compare(left.").Append(state.KeyMember.Name).Append(", right.").Append(state.KeyMember.Name).Append(@") > 0; } /// - public static bool operator >=(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator >=(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(leftNullCheck).Append(rightNullCheck).Append("return global::System.StringComparer.OrdinalIgnoreCase.Compare(left.").Append(state.KeyMember.Name).Append(", right.").Append(state.KeyMember.Name).Append(@") >= 0; }"); @@ -248,13 +248,13 @@ private static void GenerateKeyOverloadsUsingOperators( sb.Append(@" /// - public static bool operator <(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static bool operator <(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return left.").Append(state.KeyMember.Name).Append(@" < right; } /// - public static bool operator <(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator <(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeRightNullCheck).Append("return left < right.").Append(state.KeyMember.Name).Append(@"; }"); @@ -265,13 +265,13 @@ private static void GenerateKeyOverloadsUsingOperators( sb.Append(@" /// - public static bool operator <=(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static bool operator <=(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return left.").Append(state.KeyMember.Name).Append(@" <= right; } /// - public static bool operator <=(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator <=(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeRightNullCheck).Append("return left <= right.").Append(state.KeyMember.Name).Append(@"; }"); @@ -282,13 +282,13 @@ private static void GenerateKeyOverloadsUsingOperators( sb.Append(@" /// - public static bool operator >(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static bool operator >(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return left.").Append(state.KeyMember.Name).Append(@" > right; } /// - public static bool operator >(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator >(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeRightNullCheck).Append("return left > right.").Append(state.KeyMember.Name).Append(@"; }"); @@ -299,13 +299,13 @@ private static void GenerateKeyOverloadsUsingOperators( sb.Append(@" /// - public static bool operator >=(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static bool operator >=(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return left.").Append(state.KeyMember.Name).Append(@" >= right; } /// - public static bool operator >=(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator >=(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeRightNullCheck).Append("return left >= right.").Append(state.KeyMember.Name).Append(@"; }"); @@ -324,49 +324,49 @@ private static void GenerateKeyOverloadsUsingComparerAccessor( sb.Append(@" /// - public static bool operator <(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static bool operator <(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return ").Append(comparerAccessor).Append(".Comparer.Compare(left.").Append(state.KeyMember.Name).Append(@", right) < 0; } /// - public static bool operator <(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator <(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeRightNullCheck).Append("return ").Append(comparerAccessor).Append(".Comparer.Compare(left, right.").Append(state.KeyMember.Name).Append(@") < 0; } /// - public static bool operator <=(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static bool operator <=(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return ").Append(comparerAccessor).Append(".Comparer.Compare(left.").Append(state.KeyMember.Name).Append(@", right) <= 0; } /// - public static bool operator <=(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator <=(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeRightNullCheck).Append("return ").Append(comparerAccessor).Append(".Comparer.Compare(left, right.").Append(state.KeyMember.Name).Append(@") <= 0; } /// - public static bool operator >(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static bool operator >(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return ").Append(comparerAccessor).Append(".Comparer.Compare(left.").Append(state.KeyMember.Name).Append(@", right) > 0; } /// - public static bool operator >(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator >(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeRightNullCheck).Append("return ").Append(comparerAccessor).Append(".Comparer.Compare(left, right.").Append(state.KeyMember.Name).Append(@") > 0; } /// - public static bool operator >=(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static bool operator >=(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return ").Append(comparerAccessor).Append(".Comparer.Compare(left.").Append(state.KeyMember.Name).Append(@", right) >= 0; } /// - public static bool operator >=(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator >=(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeRightNullCheck).Append("return ").Append(comparerAccessor).Append(".Comparer.Compare(left, right.").Append(state.KeyMember.Name).Append(@") >= 0; }"); @@ -383,49 +383,49 @@ private static void GenerateKeyOverloadsUsingOrdinalIgnoreCaseComparer( sb.Append(@" /// - public static bool operator <(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static bool operator <(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return global::System.StringComparer.OrdinalIgnoreCase.Compare(left.").Append(state.KeyMember.Name).Append(@", right) < 0; } /// - public static bool operator <(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator <(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeRightNullCheck).Append("return global::System.StringComparer.OrdinalIgnoreCase.Compare(left, right.").Append(state.KeyMember.Name).Append(@") < 0; } /// - public static bool operator <=(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static bool operator <=(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return global::System.StringComparer.OrdinalIgnoreCase.Compare(left.").Append(state.KeyMember.Name).Append(@", right) <= 0; } /// - public static bool operator <=(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator <=(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeRightNullCheck).Append("return global::System.StringComparer.OrdinalIgnoreCase.Compare(left, right.").Append(state.KeyMember.Name).Append(@") <= 0; } /// - public static bool operator >(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static bool operator >(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return global::System.StringComparer.OrdinalIgnoreCase.Compare(left.").Append(state.KeyMember.Name).Append(@", right) > 0; } /// - public static bool operator >(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator >(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeRightNullCheck).Append("return global::System.StringComparer.OrdinalIgnoreCase.Compare(left, right.").Append(state.KeyMember.Name).Append(@") > 0; } /// - public static bool operator >=(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static bool operator >=(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return global::System.StringComparer.OrdinalIgnoreCase.Compare(left.").Append(state.KeyMember.Name).Append(@", right) >= 0; } /// - public static bool operator >=(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static bool operator >=(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeRightNullCheck).Append("return global::System.StringComparer.OrdinalIgnoreCase.Compare(left, right.").Append(state.KeyMember.Name).Append(@") >= 0; }"); diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/DefaultMemberState.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/DefaultMemberState.cs index 2273b87e..27a858c1 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/DefaultMemberState.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/DefaultMemberState.cs @@ -9,13 +9,7 @@ public sealed class DefaultMemberState : IMemberState, IEquatable _typedMemberState.SpecialType; public string TypeFullyQualified => _typedMemberState.TypeFullyQualified; - public string TypeFullyQualifiedNullAnnotated => _typedMemberState.TypeFullyQualifiedNullAnnotated; - public string TypeFullyQualifiedWithNullability => _typedMemberState.TypeFullyQualifiedWithNullability; public bool IsReferenceType => _typedMemberState.IsReferenceType; - public bool IsFormattable => _typedMemberState.IsFormattable; - public bool IsComparable => _typedMemberState.IsComparable; - public bool IsParsable => _typedMemberState.IsParsable; - public ImplementedComparisonOperators ComparisonOperators => _typedMemberState.ComparisonOperators; public bool IsNullableStruct => _typedMemberState.IsNullableStruct; public NullableAnnotation NullableAnnotation => _typedMemberState.NullableAnnotation; diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/DesiredFactory.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/DesiredFactory.cs index b2079303..490acbda 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/DesiredFactory.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/DesiredFactory.cs @@ -11,7 +11,7 @@ public sealed class DesiredFactory : ITypeFullyQualified, IEquatable"); + global::System.Numerics.IEqualityOperators<").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.Type).Append(", bool>"); if (!_withKeyTypeOverloads || state.KeyMember is null) return; sb.Append(@", - global::System.Numerics.IEqualityOperators<").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.KeyMember.TypeFullyQualified).Append(", bool>"); + global::System.Numerics.IEqualityOperators<").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.KeyMember).Append(", bool>"); } public void GenerateImplementation(StringBuilder sb, EqualityComparisonOperatorsGeneratorState state) @@ -76,7 +76,7 @@ private static void GenerateUsingEquals(StringBuilder sb, EqualityComparisonOper /// Instance to compare. /// Another instance to compare. /// true if objects are equal; otherwise false. - public static bool operator ==(").Append(state.Type.TypeFullyQualifiedNullAnnotated).Append(" obj, ").Append(state.Type.TypeFullyQualifiedNullAnnotated).Append(@" other) + public static bool operator ==(").AppendTypeFullyQualifiedNullAnnotated(state.Type).Append(" obj, ").AppendTypeFullyQualifiedNullAnnotated(state.Type).Append(@" other) {"); if (state.Type.IsReferenceType) @@ -110,7 +110,7 @@ private static void GenerateUsingEquals(StringBuilder sb, EqualityComparisonOper /// Instance to compare. /// Another instance to compare. /// false if objects are equal; otherwise true. - public static bool operator !=(").Append(state.Type.TypeFullyQualifiedNullAnnotated).Append(" obj, ").Append(state.Type.TypeFullyQualifiedNullAnnotated).Append(@" other) + public static bool operator !=(").AppendTypeFullyQualifiedNullAnnotated(state.Type).Append(" obj, ").AppendTypeFullyQualifiedNullAnnotated(state.Type).Append(@" other) { return !(obj == other); }"); @@ -125,7 +125,7 @@ private void GenerateKeyOverloads( sb.Append(@" - private static bool Equals(").Append(state.Type.TypeFullyQualifiedNullAnnotated).Append(" obj, ").Append(state.KeyMember.TypeFullyQualified).Append(@" value) + private static bool Equals(").AppendTypeFullyQualifiedNullAnnotated(state.Type).Append(" obj, ").AppendTypeFullyQualified(state.KeyMember).Append(@" value) {"); if (state.Type.IsReferenceType) @@ -175,45 +175,45 @@ private static bool Equals(").Append(state.Type.TypeFullyQualifiedNullAnnotated) } /// - /// Compares an instance of with . + /// Compares an instance of with . /// /// Instance to compare. /// Value to compare with. /// true if objects are equal; otherwise false. - public static bool operator ==(").Append(state.Type.TypeFullyQualifiedNullAnnotated).Append(" obj, ").Append(state.KeyMember.TypeFullyQualified).Append(@" value) + public static bool operator ==(").AppendTypeFullyQualifiedNullAnnotated(state.Type).Append(" obj, ").AppendTypeFullyQualified(state.KeyMember).Append(@" value) { return Equals(obj, value); } /// - /// Compares an instance of with . + /// Compares an instance of with . /// /// Value to compare. /// Instance to compare with. /// true if objects are equal; otherwise false. - public static bool operator ==(").Append(state.KeyMember.TypeFullyQualified).Append(" value, ").Append(state.Type.TypeFullyQualifiedNullAnnotated).Append(@" obj) + public static bool operator ==(").AppendTypeFullyQualified(state.KeyMember).Append(" value, ").AppendTypeFullyQualifiedNullAnnotated(state.Type).Append(@" obj) { return Equals(obj, value); } /// - /// Compares an instance of with . + /// Compares an instance of with . /// /// Instance to compare. /// Value to compare with. /// false if objects are equal; otherwise true. - public static bool operator !=(").Append(state.Type.TypeFullyQualifiedNullAnnotated).Append(" obj, ").Append(state.KeyMember.TypeFullyQualified).Append(@" value) + public static bool operator !=(").AppendTypeFullyQualifiedNullAnnotated(state.Type).Append(" obj, ").AppendTypeFullyQualified(state.KeyMember).Append(@" value) { return !(obj == value); } /// - /// Compares an instance of with . + /// Compares an instance of with . /// /// Value to compare. /// Instance to compare with. /// false if objects are equal; otherwise true. - public static bool operator !=(").Append(state.KeyMember.TypeFullyQualified).Append(" value, ").Append(state.Type.TypeFullyQualifiedNullAnnotated).Append(@" obj) + public static bool operator !=(").AppendTypeFullyQualified(state.KeyMember).Append(" value, ").AppendTypeFullyQualifiedNullAnnotated(state.Type).Append(@" obj) { return !(obj == value); }"); diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/IMemberInformation.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/IMemberInformation.cs index 479ab3d2..ea09086d 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/IMemberInformation.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/IMemberInformation.cs @@ -1,8 +1,7 @@ namespace Thinktecture.CodeAnalysis; -public interface IMemberInformation : ITypeFullyQualified +public interface IMemberInformation : ITypeInformationWithNullability { string Name { get; } - bool IsReferenceType { get; } SpecialType SpecialType { get; } } diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/IMemberState.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/IMemberState.cs index f79d19d5..75a89410 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/IMemberState.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/IMemberState.cs @@ -3,8 +3,4 @@ namespace Thinktecture.CodeAnalysis; public interface IMemberState : IEquatable, IMemberInformation, IHashCodeComputable { ArgumentName ArgumentName { get; } - string TypeFullyQualifiedNullAnnotated { get; } - string TypeFullyQualifiedWithNullability { get; } - bool IsNullableStruct { get; } - NullableAnnotation NullableAnnotation { get; } } diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ITypeInformation.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ITypeInformation.cs index c578455f..781a5e00 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ITypeInformation.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ITypeInformation.cs @@ -1,9 +1,7 @@ namespace Thinktecture.CodeAnalysis; -public interface ITypeInformation : INamespaceAndName, ITypeFullyQualified +public interface ITypeInformation : INamespaceAndName, ITypeInformationWithNullability { string TypeMinimallyQualified { get; } - string TypeFullyQualifiedNullAnnotated { get; } - bool IsReferenceType { get; } bool IsEqualWithReferenceEquality { get; } } diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ITypeInformationWithNullability.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ITypeInformationWithNullability.cs new file mode 100644 index 00000000..e20940c3 --- /dev/null +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ITypeInformationWithNullability.cs @@ -0,0 +1,8 @@ +namespace Thinktecture.CodeAnalysis; + +public interface ITypeInformationWithNullability : ITypeFullyQualified +{ + bool IsReferenceType { get; } + NullableAnnotation NullableAnnotation { get; } + bool IsNullableStruct { get; } +} diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ITypedMemberState.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ITypedMemberState.cs index 044357d5..42ce9f8f 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ITypedMemberState.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ITypedMemberState.cs @@ -3,9 +3,6 @@ namespace Thinktecture.CodeAnalysis; public interface ITypedMemberState : IEquatable { string TypeFullyQualified { get; } - string TypeFullyQualifiedNullable { get; } - string TypeFullyQualifiedNullAnnotated { get; } - string TypeFullyQualifiedWithNullability { get; } string TypeMinimallyQualified { get; } SpecialType SpecialType { get; } bool IsReferenceType { get; } diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/InstanceMemberInfo.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/InstanceMemberInfo.cs index d4f79a46..bc772b13 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/InstanceMemberInfo.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/InstanceMemberInfo.cs @@ -18,17 +18,11 @@ public sealed class InstanceMemberInfo : IMemberState, IEquatable _typedMemberState.SpecialType; public string TypeFullyQualified => _typedMemberState.TypeFullyQualified; - public string TypeFullyQualifiedNullAnnotated => _typedMemberState.TypeFullyQualifiedNullAnnotated; - public string TypeFullyQualifiedWithNullability => _typedMemberState.TypeFullyQualifiedWithNullability; public string TypeMinimallyQualified => _typedMemberState.TypeMinimallyQualified; public bool IsReferenceType => _typedMemberState.IsReferenceType; public bool IsReferenceTypeOrNullableStruct => _typedMemberState.IsReferenceTypeOrNullableStruct; - public bool IsFormattable => _typedMemberState.IsFormattable; - public bool IsComparable => _typedMemberState.IsComparable; - public bool IsParsable => _typedMemberState.IsParsable; public bool IsNullableStruct => _typedMemberState.IsNullableStruct; public NullableAnnotation NullableAnnotation => _typedMemberState.NullableAnnotation; - public ImplementedComparisonOperators ComparisonOperators => _typedMemberState.ComparisonOperators; private InstanceMemberInfo( ITypedMemberState typedMemberState, diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyMemberState.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyMemberState.cs index c5538577..b12f1f61 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyMemberState.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyMemberState.cs @@ -11,9 +11,6 @@ public sealed class KeyMemberState : IMemberState, IEquatable public SpecialType SpecialType => _typedMemberState.SpecialType; public string TypeFullyQualified => _typedMemberState.TypeFullyQualified; - public string TypeFullyQualifiedNullable => _typedMemberState.TypeFullyQualifiedNullable; - public string TypeFullyQualifiedNullAnnotated => _typedMemberState.TypeFullyQualifiedNullAnnotated; - public string TypeFullyQualifiedWithNullability => _typedMemberState.TypeFullyQualifiedWithNullability; public bool IsReferenceType => _typedMemberState.IsReferenceType; public bool IsFormattable => _typedMemberState.IsFormattable; public bool IsComparable => _typedMemberState.IsComparable; diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyedJsonCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyedJsonCodeGenerator.cs index 67c905db..f9c3ab21 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyedJsonCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyedJsonCodeGenerator.cs @@ -42,7 +42,7 @@ namespace ").Append(_state.Type.Namespace).Append(@"; if (!isString) _sb.Append(keyType).Append(", "); - _sb.Append(_state.AttributeInfo.ValidationError.TypeFullyQualified).Append(@">))] + _sb.AppendTypeFullyQualified(_state.AttributeInfo.ValidationError).Append(@">))] partial ").Append(_state.Type.IsReferenceType ? "class" : "struct").Append(" ").Append(_state.Type.Name).Append(@" { } diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyedMessagePackCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyedMessagePackCodeGenerator.cs index 2e1c71b3..c9d0288c 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyedMessagePackCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyedMessagePackCodeGenerator.cs @@ -34,7 +34,7 @@ namespace ").Append(_state.Type.Namespace).Append(@"; } _sb.Append(@" -[global::MessagePack.MessagePackFormatter(typeof(global::Thinktecture.Formatters.").Append(_state.Type.IsReferenceType ? "ValueObjectMessagePackFormatter" : "StructValueObjectMessagePackFormatter").Append("<").Append(_state.Type.TypeFullyQualified).Append(", ").Append(keyType).Append(", ").Append(_state.AttributeInfo.ValidationError.TypeFullyQualified).Append(@">))] +[global::MessagePack.MessagePackFormatter(typeof(global::Thinktecture.Formatters.").Append(_state.Type.IsReferenceType ? "ValueObjectMessagePackFormatter" : "StructValueObjectMessagePackFormatter").Append("<").AppendTypeFullyQualified(_state.Type).Append(", ").Append(keyType).Append(", ").Append(_state.AttributeInfo.ValidationError.TypeFullyQualified).Append(@">))] partial ").Append(_state.Type.IsReferenceType ? "class" : "struct").Append(" ").Append(_state.Type.Name).Append(@" { } diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyedNewtonsoftJsonCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyedNewtonsoftJsonCodeGenerator.cs index 5f063130..69c1fb1b 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyedNewtonsoftJsonCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/KeyedNewtonsoftJsonCodeGenerator.cs @@ -34,7 +34,7 @@ namespace ").Append(_state.Type.Namespace).Append(@"; } _sb.Append(@" -[global::Newtonsoft.Json.JsonConverterAttribute(typeof(global::Thinktecture.Json.ValueObjectNewtonsoftJsonConverter<").Append(_state.Type.TypeFullyQualified).Append(", ").Append(keyType).Append(", ").Append(_state.AttributeInfo.ValidationError.TypeFullyQualified).Append(@">))] +[global::Newtonsoft.Json.JsonConverterAttribute(typeof(global::Thinktecture.Json.ValueObjectNewtonsoftJsonConverter<").AppendTypeFullyQualified(_state.Type).Append(", ").Append(keyType).Append(", ").AppendTypeFullyQualified(_state.AttributeInfo.ValidationError).Append(@">))] partial ").Append(_state.Type.IsReferenceType ? "class" : "struct").Append(" ").Append(_state.Type.Name).Append(@" { } diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ParsableCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ParsableCodeGenerator.cs index e006ed4d..ec8c58f7 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ParsableCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ParsableCodeGenerator.cs @@ -20,7 +20,7 @@ private ParsableCodeGenerator(bool isForValidatableEnum) public void GenerateBaseTypes(StringBuilder sb, ParsableGeneratorState state) { sb.Append(@" - global::System.IParsable<").Append(state.Type.TypeFullyQualified).Append(">"); + global::System.IParsable<").AppendTypeFullyQualified(state.Type).Append(">"); } public void GenerateImplementation(StringBuilder sb, ParsableGeneratorState state) @@ -34,8 +34,8 @@ private static void GenerateValidate(StringBuilder sb, ParsableGeneratorState st { var keyType = state.KeyMember?.IsString() == true || state.HasStringBasedValidateMethod ? "string" : state.KeyMember?.TypeFullyQualified; sb.Append(@" - private static ").Append(state.ValidationError.TypeFullyQualified).Append("? Validate(").Append(keyType).Append(" key, global::System.IFormatProvider? provider, out ").Append(state.Type.TypeFullyQualifiedNullAnnotated).Append(@" result) - where T : global::Thinktecture.IValueObjectFactory<").Append(state.Type.TypeFullyQualified).Append(", ").Append(keyType).Append(", ").Append(state.ValidationError.TypeFullyQualified).Append(@"> + private static ").AppendTypeFullyQualified(state.ValidationError).Append("? Validate(").Append(keyType).Append(" key, global::System.IFormatProvider? provider, out ").AppendTypeFullyQualifiedNullAnnotated(state.Type).Append(@" result) + where T : global::Thinktecture.IValueObjectFactory<").AppendTypeFullyQualified(state.Type).Append(", ").Append(keyType).Append(", ").AppendTypeFullyQualified(state.ValidationError).Append(@"> { return T.Validate(key, provider, out result); }"); @@ -46,19 +46,19 @@ private void GenerateParse(StringBuilder sb, ParsableGeneratorState state) sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(@" Parse(string s, global::System.IFormatProvider? provider) + public static ").AppendTypeFullyQualified(state.Type).Append(@" Parse(string s, global::System.IFormatProvider? provider) {"); if (state.KeyMember?.IsString() == true || state.HasStringBasedValidateMethod) { sb.Append(@" - var validationError = Validate<").Append(state.Type.TypeFullyQualified).Append(">(s, provider, out var result);"); + var validationError = Validate<").AppendTypeFullyQualified(state.Type).Append(">(s, provider, out var result);"); } else if (state.KeyMember is not null) { sb.Append(@" - var key = ").Append(state.KeyMember.TypeFullyQualified).Append(@".Parse(s, provider); - var validationError = Validate<").Append(state.Type.TypeFullyQualified).Append(">(key, provider, out var result);"); + var key = ").AppendTypeFullyQualified(state.KeyMember).Append(@".Parse(s, provider); + var validationError = Validate<").AppendTypeFullyQualified(state.Type).Append(">(key, provider, out var result);"); } if (_isForValidatableEnum) @@ -87,7 +87,7 @@ private void GenerateTryParse(StringBuilder sb, ParsableGeneratorState state) public static bool TryParse( string? s, global::System.IFormatProvider? provider, - [global::System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out ").Append(state.Type.TypeFullyQualified).Append(@" result) + [global::System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out ").AppendTypeFullyQualified(state.Type).Append(@" result) { if(s is null) { @@ -99,7 +99,7 @@ public static bool TryParse( { sb.Append(@" - var validationError = Validate<").Append(state.Type.TypeFullyQualified).Append(">(s, provider, out result!);"); + var validationError = Validate<").AppendTypeFullyQualified(state.Type).Append(">(s, provider, out result!);"); } else if (state.KeyMember is not null) { @@ -111,7 +111,7 @@ public static bool TryParse( return false; } - var validationError = Validate<").Append(state.Type.TypeFullyQualified).Append(">(key, provider, out result!);"); + var validationError = Validate<").AppendTypeFullyQualified(state.Type).Append(">(key, provider, out result!);"); } if (_isForValidatableEnum) diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnumAndValueObjectCodeGeneratorBase.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnumAndValueObjectCodeGeneratorBase.cs index f3eb7fd5..8faef0f7 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnumAndValueObjectCodeGeneratorBase.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnumAndValueObjectCodeGeneratorBase.cs @@ -11,7 +11,7 @@ protected void GenerateKeyMember(StringBuilder sb, KeyMemberState keyMember, boo /// /// The identifier of this ").Append(isEnum ? "item" : "object").Append(@". /// - ").RenderAccessModifier(keyMember.AccessModifier).Append(" ").Append(keyMember.Kind == ValueObjectMemberKind.Field ? "readonly " : null).Append(keyMember.TypeFullyQualified).Append(" ").Append(keyMember.Name).Append(keyMember.Kind == ValueObjectMemberKind.Property ? " { get; }" : ";"); + ").RenderAccessModifier(keyMember.AccessModifier).Append(" ").Append(keyMember.Kind == ValueObjectMemberKind.Field ? "readonly " : null).AppendTypeFullyQualified(keyMember).Append(" ").Append(keyMember.Name).Append(keyMember.Kind == ValueObjectMemberKind.Property ? " { get; }" : ";"); } protected void GenerateKeyMemberEqualityComparison(StringBuilder sb, KeyMemberState keyMember, string? keyMemberEqualityComparerAccessor) diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnums/DerivedTypesCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnums/DerivedTypesCodeGenerator.cs index d3c1f6a8..09dba6b1 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnums/DerivedTypesCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnums/DerivedTypesCodeGenerator.cs @@ -34,7 +34,7 @@ namespace ").Append(_state.Namespace).Append(@"; [global::System.Runtime.CompilerServices.ModuleInitializer] internal static void DerivedTypesModuleInit() { - var enumType = typeof(").Append(_state.TypeFullyQualified).Append(");"); + var enumType = typeof(").AppendTypeFullyQualified(_state).Append(");"); foreach (var derivedType in _state.DerivedTypesFullyQualified) { diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnums/EnumSourceGeneratorState.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnums/EnumSourceGeneratorState.cs index 398e3481..51a20a2e 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnums/EnumSourceGeneratorState.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnums/EnumSourceGeneratorState.cs @@ -5,7 +5,6 @@ public sealed class EnumSourceGeneratorState : ITypeInformation, IEquatable !Settings.IsValidatable; @@ -16,6 +15,8 @@ public sealed class EnumSourceGeneratorState : ITypeInformation, IEquatable))]"); + [global::System.ComponentModel.TypeConverter(typeof(global::Thinktecture.ValueObjectTypeConverter<").AppendTypeFullyQualified(_state).Append(", ").AppendTypeFullyQualified(_state.KeyMember).Append(", ").AppendTypeFullyQualified(_state.ValidationError).Append(">))]"); } _sb.Append(@" partial ").Append(_state.IsReferenceType ? "class" : "struct").Append(" ").Append(_state.Name).Append(" :"); if (_state.KeyMember is not null) - _sb.Append(" global::Thinktecture.IEnum<").Append(_state.KeyMember.TypeFullyQualified).Append(", ").Append(_state.TypeFullyQualified).Append(", ").Append(_state.ValidationError.TypeFullyQualified).Append(">,"); + _sb.Append(" global::Thinktecture.IEnum<").AppendTypeFullyQualified(_state.KeyMember).Append(", ").AppendTypeFullyQualified(_state).Append(", ").AppendTypeFullyQualified(_state.ValidationError).Append(">,"); foreach (var desiredFactory in _state.Settings.DesiredFactories) { @@ -66,12 +66,12 @@ private void GenerateEnum(CancellationToken cancellationToken) continue; _sb.Append(@" - global::Thinktecture.IValueObjectFactory<").Append(_state.TypeFullyQualified).Append(", ").Append(desiredFactory.TypeFullyQualified).Append(", ").Append(_state.ValidationError.TypeFullyQualified).Append(">,"); + global::Thinktecture.IValueObjectFactory<").AppendTypeFullyQualified(_state).Append(", ").AppendTypeFullyQualified(desiredFactory).Append(", ").AppendTypeFullyQualified(_state.ValidationError).Append(">,"); if (desiredFactory.UseForSerialization != SerializationFrameworks.None) { _sb.Append(@" - global::Thinktecture.IValueObjectConvertable<").Append(desiredFactory.TypeFullyQualified).Append(">,"); + global::Thinktecture.IValueObjectConvertable<").AppendTypeFullyQualified(desiredFactory).Append(">,"); } } @@ -82,7 +82,7 @@ private void GenerateEnum(CancellationToken cancellationToken) } _sb.Append(@" - global::System.IEquatable<").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@"> + global::System.IEquatable<").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@"> {"); if (_state.KeyMember is not null) @@ -91,29 +91,29 @@ private void GenerateEnum(CancellationToken cancellationToken) _sb.Append(@" - private static readonly global::System.Lazy> _itemsLookup - = new global::System.Lazy>(GetLookup, global::System.Threading.LazyThreadSafetyMode.PublicationOnly); + private static readonly global::System.Lazy> _itemsLookup + = new global::System.Lazy>(GetLookup, global::System.Threading.LazyThreadSafetyMode.PublicationOnly); - private static readonly global::System.Lazy> _items - = new global::System.Lazy>(() => global::System.Linq.Enumerable.ToList(_itemsLookup.Value.Values).AsReadOnly(), global::System.Threading.LazyThreadSafetyMode.PublicationOnly); + private static readonly global::System.Lazy> _items + = new global::System.Lazy>(() => global::System.Linq.Enumerable.ToList(_itemsLookup.Value.Values).AsReadOnly(), global::System.Threading.LazyThreadSafetyMode.PublicationOnly); /// /// Gets all valid items. /// - public static global::System.Collections.Generic.IReadOnlyList<").Append(_state.TypeFullyQualified).Append("> Items => _items.Value;"); + public static global::System.Collections.Generic.IReadOnlyList<").AppendTypeFullyQualified(_state).Append("> Items => _items.Value;"); GenerateKeyMember(_sb, _state.KeyMember, true); } else { _sb.Append(@" - private static readonly global::System.Lazy> _items - = new global::System.Lazy>(GetItems, global::System.Threading.LazyThreadSafetyMode.PublicationOnly); + private static readonly global::System.Lazy> _items + = new global::System.Lazy>(GetItems, global::System.Threading.LazyThreadSafetyMode.PublicationOnly); /// /// Gets all valid items. /// - public static global::System.Collections.Generic.IReadOnlyList<").Append(_state.TypeFullyQualified).Append("> Items => _items.Value;"); + public static global::System.Collections.Generic.IReadOnlyList<").AppendTypeFullyQualified(_state).Append("> Items => _items.Value;"); } if (_state.KeyMember is not null && _state.Settings.IsValidatable) @@ -162,7 +162,7 @@ private void GenerateEnum(CancellationToken cancellationToken) /// public override bool Equals(object? other) { - return other is ").Append(_state.TypeFullyQualified).Append(@" item && Equals(item); + return other is ").AppendTypeFullyQualified(_state).Append(@" item && Equals(item); } /// @@ -434,21 +434,18 @@ private void GenerateMap() private void GenerateModuleInitializer(IMemberState keyMember) { - var enumType = _state.TypeFullyQualified; - var enumTypeNullAnnotated = _state.TypeFullyQualifiedNullAnnotated; - _sb.Append(@" [global::System.Runtime.CompilerServices.ModuleInitializer] internal static void ModuleInit() { - var convertFromKey = new global::System.Func<").Append(keyMember.TypeFullyQualifiedNullAnnotated).Append(", ").Append(enumTypeNullAnnotated).Append(">(").Append(enumType).Append(@".Get); - global::System.Linq.Expressions.Expression> convertFromKeyExpression = static ").Append(keyMember.ArgumentName.Escaped).Append(" => ").Append(enumType).Append(".").Append(Constants.Methods.GET).Append("(").Append(keyMember.ArgumentName.Escaped).Append(@"); + var convertFromKey = new global::System.Func<").AppendTypeFullyQualifiedNullAnnotated(keyMember).Append(", ").AppendTypeFullyQualifiedNullAnnotated(_state).Append(">(").AppendTypeFullyQualified(_state).Append(@".Get); + global::System.Linq.Expressions.Expression> convertFromKeyExpression = static ").Append(keyMember.ArgumentName.Escaped).Append(" => ").AppendTypeFullyQualified(_state).Append(".").Append(Constants.Methods.GET).Append("(").Append(keyMember.ArgumentName.Escaped).Append(@"); - var convertToKey = new global::System.Func<").Append(enumType).Append(", ").Append(keyMember.TypeFullyQualified).Append(">(static item => item.").Append(keyMember.Name).Append(@"); - global::System.Linq.Expressions.Expression> convertToKeyExpression = static item => item.").Append(keyMember.Name).Append(@"; + var convertToKey = new global::System.Func<").AppendTypeFullyQualified(_state).Append(", ").AppendTypeFullyQualified(keyMember).Append(">(static item => item.").Append(keyMember.Name).Append(@"); + global::System.Linq.Expressions.Expression> convertToKeyExpression = static item => item.").Append(keyMember.Name).Append(@"; - var enumType = typeof(").Append(enumType).Append(@"); - var metadata = new global::Thinktecture.Internal.KeyedValueObjectMetadata(enumType, typeof(").Append(keyMember.TypeFullyQualified).Append("), true, ").Append(_state.Settings.IsValidatable ? "true" : "false").Append(@", convertFromKey, convertFromKeyExpression, null, convertToKey, convertToKeyExpression); + var enumType = typeof(").AppendTypeFullyQualified(_state).Append(@"); + var metadata = new global::Thinktecture.Internal.KeyedValueObjectMetadata(enumType, typeof(").AppendTypeFullyQualified(keyMember).Append("), true, ").Append(_state.Settings.IsValidatable ? "true" : "false").Append(@", convertFromKey, convertFromKeyExpression, null, convertToKey, convertToKeyExpression); global::Thinktecture.Internal.KeyedValueObjectMetadataLookup.AddMetadata(enumType, metadata); }"); @@ -464,7 +461,7 @@ private void GenerateTryGet(IMemberState keyProperty) /// The identifier to return an enumeration item for. /// An instance of . /// true if a valid item with provided exists; false otherwise. - public static bool TryGet([global::System.Diagnostics.CodeAnalysis.AllowNull] ").Append(keyProperty.TypeFullyQualified).Append(" ").Append(keyProperty.ArgumentName.Escaped).Append(", [global::System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out ").Append(_state.TypeFullyQualified).Append(@" item) + public static bool TryGet([global::System.Diagnostics.CodeAnalysis.AllowNull] ").AppendTypeFullyQualified(keyProperty).Append(" ").Append(keyProperty.ArgumentName.Escaped).Append(", [global::System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out ").AppendTypeFullyQualified(_state).Append(@" item) {"); if (keyProperty.IsReferenceType) @@ -509,10 +506,10 @@ private void GenerateValidate(IMemberState keyProperty) /// The identifier to return an enumeration item for. /// An object that provides culture-specific formatting information. /// An instance of . - /// null if a valid item with provided exists; with an error message otherwise. - public static ").Append(_state.ValidationError.TypeFullyQualified).Append("? Validate([global::System.Diagnostics.CodeAnalysis.AllowNull] ").Append(keyProperty.TypeFullyQualified).Append(" ").Append(keyProperty.ArgumentName.Escaped).Append(", global::System.IFormatProvider? ").Append(providerArgumentName).Append(", [global::System.Diagnostics.CodeAnalysis.MaybeNull] out ").Append(_state.TypeFullyQualified).Append(@" item) + /// null if a valid item with provided exists; with an error message otherwise. + public static ").AppendTypeFullyQualified(_state.ValidationError).Append("? Validate([global::System.Diagnostics.CodeAnalysis.AllowNull] ").AppendTypeFullyQualified(keyProperty).Append(" ").Append(keyProperty.ArgumentName.Escaped).Append(", global::System.IFormatProvider? ").Append(providerArgumentName).Append(", [global::System.Diagnostics.CodeAnalysis.MaybeNull] out ").AppendTypeFullyQualified(_state).Append(@" item) { - if(").Append(_state.TypeFullyQualified).Append(".TryGet(").Append(keyProperty.ArgumentName.Escaped).Append(@", out item)) + if(").AppendTypeFullyQualified(_state).Append(".TryGet(").Append(keyProperty.ArgumentName.Escaped).Append(@", out item)) { return null; } @@ -535,7 +532,7 @@ private void GenerateValidate(IMemberState keyProperty) } _sb.Append(@" - return global::Thinktecture.Internal.ValidationErrorCreator.CreateValidationError<").Append(_state.ValidationError.TypeFullyQualified).Append(@">($""There is no item of type '").Append(_state.TypeMinimallyQualified).Append("' with the identifier '{").Append(keyProperty.ArgumentName.Escaped).Append(@"}'.""); + return global::Thinktecture.Internal.ValidationErrorCreator.CreateValidationError<").AppendTypeFullyQualified(_state.ValidationError).Append(@">($""There is no item of type '").Append(_state.TypeMinimallyQualified).Append("' with the identifier '{").Append(keyProperty.ArgumentName.Escaped).Append(@"}'.""); } }"); } @@ -545,12 +542,12 @@ private void GenerateImplicitConversion(IMemberState keyProperty) _sb.Append(@" /// - /// Implicit conversion to the type . + /// Implicit conversion to the type . /// /// Item to covert. /// The of provided or default if is null. [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""item"")] - public static implicit operator ").Append(keyProperty.TypeFullyQualifiedNullAnnotated).Append("(").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" item) + public static implicit operator ").AppendTypeFullyQualifiedNullAnnotated(keyProperty).Append("(").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" item) {"); if (_state.IsReferenceType) @@ -573,14 +570,14 @@ private void GenerateExplicitConversion(IMemberState keyProperty) _sb.Append(@" /// - /// Explicit conversion from the type . + /// Explicit conversion from the type . /// /// Value to covert. /// An instance of if the is a known item or implements . [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""").Append(keyProperty.ArgumentName.Escaped).Append(@""")] - public static explicit operator ").Append(_state.TypeFullyQualifiedNullAnnotated).Append("(").Append(keyProperty.TypeFullyQualifiedNullAnnotated).Append(" ").Append(keyProperty.ArgumentName.Escaped).Append(@") + public static explicit operator ").AppendTypeFullyQualifiedNullAnnotated(_state).Append("(").AppendTypeFullyQualifiedNullAnnotated(keyProperty).Append(" ").Append(keyProperty.ArgumentName.Escaped).Append(@") { - return ").Append(_state.TypeFullyQualified).Append(".").Append(Constants.Methods.GET).Append("(").Append(keyProperty.ArgumentName.Escaped).Append(@"); + return ").AppendTypeFullyQualified(_state).Append(".").Append(Constants.Methods.GET).Append("(").Append(keyProperty.ArgumentName.Escaped).Append(@"); }"); } @@ -589,7 +586,7 @@ private void GenerateEquals() _sb.Append(@" /// - public bool Equals(").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" other) + public bool Equals(").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" other) {"); if (_state.Settings.IsValidatable) @@ -649,9 +646,9 @@ private void GenerateGetLookup(KeyMemberState keyMember) _sb.Append(@" - private static global::System.Collections.Generic.IReadOnlyDictionary<").Append(keyMember.TypeFullyQualified).Append(", ").Append(_state.TypeFullyQualified).Append(@"> GetLookup() + private static global::System.Collections.Generic.IReadOnlyDictionary<").AppendTypeFullyQualified(keyMember).Append(", ").AppendTypeFullyQualified(_state).Append(@"> GetLookup() { - var lookup = new global::System.Collections.Generic.Dictionary<").Append(keyMember.TypeFullyQualified).Append(", ").Append(_state.TypeFullyQualified).Append(">(").Append(totalNumberOfItems); + var lookup = new global::System.Collections.Generic.Dictionary<").AppendTypeFullyQualified(keyMember).Append(", ").AppendTypeFullyQualified(_state).Append(">(").Append(totalNumberOfItems); if (_state.Settings.KeyMemberEqualityComparerAccessor is not null) { @@ -668,7 +665,7 @@ private void GenerateGetLookup(KeyMemberState keyMember) { _sb.Append(@" - void AddItem(").Append(_state.TypeFullyQualified).Append(@" item, string itemName) + void AddItem(").AppendTypeFullyQualified(_state).Append(@" item, string itemName) {"); if (_state.IsReferenceType) @@ -739,15 +736,15 @@ private void GenerateGetItems() _sb.Append(@" - private static global::System.Collections.Generic.IReadOnlyList<").Append(_state.TypeFullyQualified).Append(@"> GetItems() + private static global::System.Collections.Generic.IReadOnlyList<").AppendTypeFullyQualified(_state).Append(@"> GetItems() { - var list = new global::System.Collections.Generic.List<").Append(_state.TypeFullyQualified).Append(">(").Append(totalNumberOfItems).Append(");"); + var list = new global::System.Collections.Generic.List<").AppendTypeFullyQualified(_state).Append(">(").Append(totalNumberOfItems).Append(");"); if (_state.ItemNames.Count > 0) { _sb.Append(@" - void AddItem(").Append(_state.TypeFullyQualified).Append(@" item, string itemName) + void AddItem(").AppendTypeFullyQualified(_state).Append(@" item, string itemName) { if (item is null) throw new global::System.ArgumentNullException($""The item \""{itemName}\"" of type \""").Append(_state.TypeMinimallyQualified).Append(@"\"" must not be null.""); @@ -794,7 +791,7 @@ private void GenerateToValue(IMemberState keyProperty) /// Gets the identifier of the item. /// [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] - ").Append(keyProperty.TypeFullyQualified).Append(" global::Thinktecture.IValueObjectConvertable<").Append(keyProperty.TypeFullyQualified).Append(@">.ToValue() + ").AppendTypeFullyQualified(keyProperty).Append(" global::Thinktecture.IValueObjectConvertable<").AppendTypeFullyQualified(keyProperty).Append(@">.ToValue() { return this.").Append(keyProperty.Name).Append(@"; }"); @@ -816,9 +813,16 @@ private void GenerateGet(IMemberState keyProperty) /// If there is no item with the provided ."); } + var returnTypeMayBeNull = _state.IsReferenceType && keyProperty.IsReferenceType; + + if (returnTypeMayBeNull) + { + _sb.Append(@" + [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""").Append(keyProperty.ArgumentName.Escaped).Append(@""")]"); + } + _sb.Append(@" - [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""").Append(keyProperty.ArgumentName.Escaped).Append(@""")] - public static ").Append(keyProperty.IsReferenceType ? _state.TypeFullyQualifiedNullAnnotated : _state.TypeFullyQualified).Append(" ").Append(Constants.Methods.GET).Append("(").Append(keyProperty.TypeFullyQualifiedNullAnnotated).Append(" ").Append(keyProperty.ArgumentName.Escaped).Append(@") + public static ").AppendTypeFullyQualified(_state, nullable: returnTypeMayBeNull).Append(" ").Append(Constants.Methods.GET).Append("(").AppendTypeFullyQualifiedNullAnnotated(keyProperty).Append(" ").Append(keyProperty.ArgumentName.Escaped).Append(@") {"); if (keyProperty.IsReferenceType) @@ -841,7 +845,7 @@ private void GenerateGet(IMemberState keyProperty) else { _sb.Append(@" - throw new global::Thinktecture.UnknownEnumIdentifierException(typeof(").Append(_state.TypeFullyQualified).Append("), ").Append(keyProperty.ArgumentName.Escaped).Append(");"); + throw new global::Thinktecture.UnknownEnumIdentifierException(typeof(").AppendTypeFullyQualified(_state).Append("), ").Append(keyProperty.ArgumentName.Escaped).Append(");"); } _sb.Append(@" @@ -855,7 +859,7 @@ private void GenerateCreateAndCheckInvalidItem(IMemberState keyProperty, bool ne { _sb.Append(@" - private static ").Append(_state.TypeFullyQualified).Append(" CreateAndCheckInvalidItem(").Append(keyProperty.TypeFullyQualified).Append(" ").Append(keyProperty.ArgumentName.Escaped).Append(@") + private static ").AppendTypeFullyQualified(_state).Append(" CreateAndCheckInvalidItem(").AppendTypeFullyQualified(keyProperty).Append(" ").Append(keyProperty.ArgumentName.Escaped).Append(@") { var item = "); @@ -901,9 +905,9 @@ private void GenerateCreateInvalidItem(IMemberState keyProperty) { _sb.Append(@" - private static ").Append(_state.TypeFullyQualified).Append(" ").Append(Constants.Methods.CREATE_INVALID_ITEM).Append("(").Append(keyProperty.TypeFullyQualified).Append(" ").Append(keyProperty.ArgumentName.Escaped).Append(@") + private static ").AppendTypeFullyQualified(_state).Append(" ").Append(Constants.Methods.CREATE_INVALID_ITEM).Append("(").AppendTypeFullyQualified(keyProperty).Append(" ").Append(keyProperty.ArgumentName.Escaped).Append(@") { - return new ").Append(_state.TypeFullyQualified).Append("(").Append(keyProperty.ArgumentName.Escaped).Append(", false"); + return new ").AppendTypeFullyQualified(_state).Append("(").Append(keyProperty.ArgumentName.Escaped).Append(", false"); foreach (var member in _state.AssignableInstanceFieldsAndProperties) { @@ -921,7 +925,7 @@ private void GenerateConstructors() { var ownCtorArgs = _state.AssignableInstanceFieldsAndProperties .Where(p => !p.IsAbstract) - .Select(a => new ConstructorArgument(a.TypeFullyQualifiedWithNullability, a.ArgumentName)) + .Select(a => new ConstructorArgument(a.TypeFullyQualified, a.ArgumentName)) .ToList(); if (_state.BaseType is null) @@ -948,7 +952,7 @@ private void GenerateConstructors() argName = $"{a.ArgumentName.Raw}{counter.ToString()}"; // rename the argument name if it collides with another argument } - return new ConstructorArgument(a.TypeFullyQualifiedWithNullability, new ArgumentName(argName, argName)); + return new ConstructorArgument(a.TypeFullyQualified, new ArgumentName(argName, argName)); }).ToList(); }) .Distinct(ConstructorArgumentsComparer.Instance) @@ -987,7 +991,7 @@ private void GenerateConstructor( if (_state.KeyMember is not null) { hasKeyMember = true; - _sb.Append(_state.KeyMember.TypeFullyQualified).Append(" ").Append(_state.KeyMember.ArgumentName.Escaped); + _sb.AppendTypeFullyQualified(_state.KeyMember).Append(" ").Append(_state.KeyMember.ArgumentName.Escaped); } else { @@ -1000,7 +1004,7 @@ private void GenerateConstructor( _sb.Append(", "); var member = ctorArgs[i]; - _sb.Append(member.TypeFullyQualifiedWithNullability).Append(" ").Append(member.ArgumentName.Escaped); + _sb.AppendTypeFullyQualified(member).Append(" ").Append(member.ArgumentName.Escaped); } _sb.Append(@") @@ -1032,7 +1036,7 @@ private void GenerateConstructor( if (_state.KeyMember is not null) { hasKeyMember = true; - _sb.Append(_state.KeyMember.TypeFullyQualified).Append(" ").Append(_state.KeyMember.ArgumentName.Escaped); + _sb.AppendTypeFullyQualified(_state.KeyMember).Append(" ").Append(_state.KeyMember.ArgumentName.Escaped); } else { @@ -1053,7 +1057,7 @@ private void GenerateConstructor( _sb.Append(", "); var member = ctorArgs[i]; - _sb.Append(member.TypeFullyQualifiedWithNullability).Append(" ").Append(member.ArgumentName.Escaped); + _sb.AppendTypeFullyQualified(member).Append(" ").Append(member.ArgumentName.Escaped); } _sb.Append(")"); @@ -1134,7 +1138,7 @@ private void GenerateConstructor( if (_state.KeyMember is not null) { _sb.Append(@" - this._hashCode = global::System.HashCode.Combine(typeof(").Append(_state.TypeFullyQualified).Append("), "); + this._hashCode = global::System.HashCode.Combine(typeof(").AppendTypeFullyQualified(_state).Append("), "); if (_state.Settings.KeyMemberEqualityComparerAccessor is not null) { @@ -1165,7 +1169,7 @@ private void GenerateConstructor( if (_state.KeyMember is not null) { - _sb.Append("ref ").Append(_state.KeyMember.TypeFullyQualified).Append(" ").Append(_state.KeyMember.ArgumentName.Escaped); + _sb.Append("ref ").AppendTypeFullyQualified(_state.KeyMember).Append(" ").Append(_state.KeyMember.ArgumentName.Escaped); } if (_state.Settings.IsValidatable) @@ -1182,13 +1186,13 @@ private void GenerateConstructor( _sb.Append(", "); var members = ctorArgs[i]; - _sb.Append("ref ").Append(members.TypeFullyQualifiedWithNullability).Append(" ").Append(members.ArgumentName.Escaped); + _sb.Append("ref ").AppendTypeFullyQualified(members).Append(" ").Append(members.ArgumentName.Escaped); } _sb.Append(");"); } - private readonly record struct ConstructorArgument(string TypeFullyQualifiedWithNullability, ArgumentName ArgumentName); + private readonly record struct ConstructorArgument(string TypeFullyQualified, ArgumentName ArgumentName) : ITypeFullyQualified; private sealed class ConstructorArgumentsComparer : IEqualityComparer> { @@ -1210,7 +1214,7 @@ public bool Equals(IReadOnlyList? x, IReadOnlyList FindDerivedTypes(INamedTypeSymbol type) return Array.Empty(); return derivedTypes - .Select(t => t.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)) + .Select(t => t.Type.ToFullyQualifiedDisplayString()) .Distinct() .ToList(); } diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/TypedMemberState.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/TypedMemberState.cs index 30ed2985..0f88d1b6 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/TypedMemberState.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/TypedMemberState.cs @@ -3,9 +3,6 @@ namespace Thinktecture.CodeAnalysis; public class TypedMemberState : IEquatable, ITypedMemberState { public string TypeFullyQualified { get; } - public string TypeFullyQualifiedNullable { get; } - public string TypeFullyQualifiedNullAnnotated => IsReferenceType ? TypeFullyQualifiedNullable : TypeFullyQualified; - public string TypeFullyQualifiedWithNullability => IsReferenceType && NullableAnnotation == NullableAnnotation.Annotated ? TypeFullyQualifiedNullAnnotated : TypeFullyQualified; public string TypeMinimallyQualified { get; } public NullableAnnotation NullableAnnotation { get; } @@ -24,8 +21,7 @@ public class TypedMemberState : IEquatable, ITypedMemberState public TypedMemberState(ITypeSymbol type) { - TypeFullyQualified = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - TypeFullyQualifiedNullable = $"{TypeFullyQualified}?"; + TypeFullyQualified = type.ToFullyQualifiedDisplayString(); TypeMinimallyQualified = type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); IsReferenceType = type.IsReferenceType; NullableAnnotation = type.NullableAnnotation; @@ -158,7 +154,7 @@ public bool Equals(TypedMemberState? other) if (ReferenceEquals(this, other)) return true; - return TypeFullyQualifiedWithNullability == other.TypeFullyQualifiedWithNullability + return TypeFullyQualified == other.TypeFullyQualified && SpecialType == other.SpecialType && IsNullableStruct == other.IsNullableStruct && IsReferenceType == other.IsReferenceType @@ -176,7 +172,7 @@ public override int GetHashCode() { unchecked { - var hashCode = TypeFullyQualifiedWithNullability.GetHashCode(); + var hashCode = TypeFullyQualified.GetHashCode(); hashCode = (hashCode * 397) ^ (int)SpecialType; hashCode = (hashCode * 397) ^ IsNullableStruct.GetHashCode(); hashCode = (hashCode * 397) ^ IsReferenceType.GetHashCode(); diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/TypedMemberStateFactoryProvider.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/TypedMemberStateFactoryProvider.cs index d5f67aea..9f4c31de 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/TypedMemberStateFactoryProvider.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/TypedMemberStateFactoryProvider.cs @@ -8,8 +8,8 @@ public class TypedMemberStateFactoryProvider private static readonly object _lock7 = new(); private static readonly object _lock8 = new(); - private static Version _version7 = new(7, 0, 0, 0); - private static Version _version8 = new(8, 0, 0, 0); + private static readonly Version _version7 = new(7, 0, 0, 0); + private static readonly Version _version8 = new(8, 0, 0, 0); private static TypedMemberStateFactory? _dotnet7; private static TypedMemberStateFactory? _dotnet8; diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/AdditionOperatorsCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/AdditionOperatorsCodeGenerator.cs index 24eab349..29aa762f 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/AdditionOperatorsCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/AdditionOperatorsCodeGenerator.cs @@ -59,13 +59,13 @@ public void GenerateBaseTypes(StringBuilder sb, InterfaceCodeGeneratorState stat return; sb.Append(@" - global::System.Numerics.IAdditionOperators<").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.Type.TypeFullyQualified).Append(">"); + global::System.Numerics.IAdditionOperators<").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.Type).Append(">"); if (!_withKeyTypeOverloads) return; sb.Append(@", - global::System.Numerics.IAdditionOperators<").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.KeyMember.TypeFullyQualified).Append(", ").Append(state.Type.TypeFullyQualified).Append(">"); + global::System.Numerics.IAdditionOperators<").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.KeyMember).Append(", ").AppendTypeFullyQualified(state.Type).Append(">"); } public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState state) @@ -78,7 +78,7 @@ public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState { sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator +(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator +(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(typeLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(" + right.").Append(state.KeyMember.Name).Append(@")); }"); @@ -89,7 +89,7 @@ public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator checked +(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator checked +(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(typeLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(checked(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(" + right.").Append(state.KeyMember.Name).Append(@"))); }"); @@ -114,13 +114,13 @@ private void GenerateOverloadsForKeyType( sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator +(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator +(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(@" + right)); } /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator +(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator +(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left + right.").Append(state.KeyMember.Name).Append(@")); }"); @@ -131,13 +131,13 @@ private void GenerateOverloadsForKeyType( sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator checked +(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator checked +(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(checked(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(@" + right))); } /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator checked +(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator checked +(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(checked(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left + right.").Append(state.KeyMember.Name).Append(@"))); }"); diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectCodeGenerator.cs index e13638cf..8f58efa2 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectCodeGenerator.cs @@ -47,19 +47,19 @@ namespace ").Append(_state.Namespace).Append(@" private void GenerateValueObject(CancellationToken cancellationToken) { _sb.Append(@" - partial ").Append(_state.IsReferenceType ? "class" : "struct").Append(" ").Append(_state.Name).Append(" : global::System.IEquatable<").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@">, - global::System.Numerics.IEqualityOperators<").Append(_state.TypeFullyQualified).Append(", ").Append(_state.TypeFullyQualified).Append(@", bool>, + partial ").Append(_state.IsReferenceType ? "class" : "struct").Append(" ").Append(_state.Name).Append(" : global::System.IEquatable<").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@">, + global::System.Numerics.IEqualityOperators<").AppendTypeFullyQualified(_state).Append(", ").AppendTypeFullyQualified(_state).Append(@", bool>, global::Thinktecture.IComplexValueObject"); foreach (var desiredFactory in _state.Settings.DesiredFactories) { _sb.Append(@", - global::Thinktecture.IValueObjectFactory<").Append(_state.TypeFullyQualified).Append(", ").Append(desiredFactory.TypeFullyQualified).Append(", ").Append(_state.ValidationError.TypeFullyQualified).Append(">"); + global::Thinktecture.IValueObjectFactory<").AppendTypeFullyQualified(_state).Append(", ").AppendTypeFullyQualified(desiredFactory).Append(", ").AppendTypeFullyQualified(_state.ValidationError).Append(">"); if (desiredFactory.UseForSerialization != SerializationFrameworks.None) { _sb.Append(@", - global::Thinktecture.IValueObjectConvertable<").Append(desiredFactory.TypeFullyQualified).Append(">"); + global::Thinktecture.IValueObjectConvertable<").AppendTypeFullyQualified(desiredFactory).Append(">"); } } @@ -69,13 +69,13 @@ private void GenerateValueObject(CancellationToken cancellationToken) GenerateModuleInitializerForComplexValueObject(); _sb.Append(@" - private static readonly int _typeHashCode = typeof(").Append(_state.TypeFullyQualified).Append(").GetHashCode();"); + private static readonly int _typeHashCode = typeof(").AppendTypeFullyQualified(_state).Append(").GetHashCode();"); if (!_state.IsReferenceType) { _sb.Append(@" - public static readonly ").Append(_state.TypeFullyQualified).Append(" ").Append(_state.Settings.DefaultInstancePropertyName).Append(" = default;"); + public static readonly ").AppendTypeFullyQualified(_state).Append(" ").Append(_state.Settings.DefaultInstancePropertyName).Append(" = default;"); } cancellationToken.ThrowIfCancellationRequested(); @@ -134,7 +134,7 @@ internal static void ModuleInit() members.Add(((global::System.Linq.Expressions.MemberExpression)arg).Member); } - var type = typeof(").Append(_state.TypeFullyQualified).Append(@"); + var type = typeof(").AppendTypeFullyQualified(_state).Append(@"); var metadata = new global::Thinktecture.Internal.ComplexValueObjectMetadata(type, members.AsReadOnly()); global::Thinktecture.Internal.ComplexValueObjectMetadataLookup.AddMetadata(type, metadata); @@ -148,7 +148,7 @@ private void GenerateCreateMethod() _sb.Append(@" - public static ").Append(_state.TypeFullyQualified).Append(" ").Append(_state.Settings.CreateFactoryMethodName).Append("(").RenderArgumentsWithType(fieldsAndProperties).Append(@") + public static ").AppendTypeFullyQualified(_state).Append(" ").Append(_state.Settings.CreateFactoryMethodName).Append("(").RenderArgumentsWithType(fieldsAndProperties).Append(@") { var validationError = Validate("); @@ -157,7 +157,7 @@ private void GenerateCreateMethod() if (fieldsAndProperties.Count > 0) _sb.Append(", "); - _sb.Append("out ").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" obj); + _sb.Append("out ").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" obj); if (validationError is not null) throw new global::System.ComponentModel.DataAnnotations.ValidationException(validationError.ToString() ?? ""Validation failed.""); @@ -178,7 +178,7 @@ private void GenerateTryCreateMethod() ", ",", trailingComma: true); _sb.Append(@" - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out ").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" obj) + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out ").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" obj) { return ").Append(_state.Settings.TryCreateFactoryMethodName).Append("("); @@ -198,8 +198,8 @@ private void GenerateTryCreateMethod() ", ",", trailingComma: true); _sb.Append(@" - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out ").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" obj, - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(false)] out ").Append(_state.ValidationError.TypeFullyQualified).Append(@"? validationError) + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out ").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" obj, + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(false)] out ").AppendTypeFullyQualified(_state.ValidationError).Append(@"? validationError) { validationError = Validate("); @@ -220,15 +220,15 @@ private void GenerateValidateMethod() _sb.Append(@" - public static ").Append(_state.ValidationError.TypeFullyQualified).Append("? Validate("); + public static ").AppendTypeFullyQualified(_state.ValidationError).Append("? Validate("); _sb.RenderArgumentsWithType(fieldsAndProperties, @" ", ",", trailingComma: true); _sb.Append(@" - out ").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" obj) + out ").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" obj) { - ").Append(_state.ValidationError.TypeFullyQualified).Append(@"? validationError = null; + ").AppendTypeFullyQualified(_state.ValidationError).Append(@"? validationError = null; "); if (_state.FactoryValidationReturnType is not null) @@ -270,7 +270,7 @@ private void GenerateValidateFactoryArguments() if (_state.FactoryValidationReturnType is not null) _sb.Append("private "); - _sb.Append("static partial ").Append(_state.FactoryValidationReturnType ?? "void").Append(" ").Append(Constants.Methods.VALIDATE_FACTORY_ARGUMENTS).Append("(ref ").Append(_state.ValidationError.TypeFullyQualified).Append("? validationError"); + _sb.Append("static partial ").Append(_state.FactoryValidationReturnType ?? "void").Append(" ").Append(Constants.Methods.VALIDATE_FACTORY_ARGUMENTS).Append("(ref ").AppendTypeFullyQualified(_state.ValidationError).Append("? validationError"); _sb.RenderArgumentsWithType(fieldsAndProperties, "ref ", leadingComma: true, addAllowNullNotNullCombi: true); @@ -293,7 +293,7 @@ private void GenerateConstructCall() { var fieldsAndProperties = _state.AssignableInstanceFieldsAndProperties; - _sb.Append("new ").Append(_state.TypeFullyQualified).Append("("); + _sb.Append("new ").AppendTypeFullyQualified(_state).Append("("); _sb.RenderArguments(fieldsAndProperties); _sb.Append(")"); @@ -309,7 +309,7 @@ private void GenerateEqualityOperators() /// Instance to compare. /// Another instance to compare. /// true if objects are equal; otherwise false. - public static bool operator ==(").Append(_state.TypeFullyQualifiedNullAnnotated).Append(" obj, ").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" other) + public static bool operator ==(").AppendTypeFullyQualifiedNullAnnotated(_state).Append(" obj, ").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" other) {"); if (_state.IsReferenceType) @@ -330,7 +330,7 @@ private void GenerateEqualityOperators() /// Instance to compare. /// Another instance to compare. /// false if objects are equal; otherwise true. - public static bool operator !=(").Append(_state.TypeFullyQualifiedNullAnnotated).Append(" obj, ").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" other) + public static bool operator !=(").AppendTypeFullyQualifiedNullAnnotated(_state).Append(" obj, ").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" other) { return !(obj == other); }"); @@ -393,11 +393,11 @@ private void GenerateEquals() /// public override bool Equals(object? other) { - return other is ").Append(_state.TypeFullyQualified).Append(@" obj && Equals(obj); + return other is ").AppendTypeFullyQualified(_state).Append(@" obj && Equals(obj); } /// - public bool Equals(").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" other) + public bool Equals(").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" other) {"); if (_state.IsReferenceType) diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectJsonCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectJsonCodeGenerator.cs index e15b4216..21d710ab 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectJsonCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectJsonCodeGenerator.cs @@ -37,7 +37,7 @@ namespace ").Append(_type.Namespace).Append(@"; [global::System.Text.Json.Serialization.JsonConverterAttribute(typeof(ValueObjectJsonConverterFactory))] partial ").Append(_type.IsReferenceType ? "class" : "struct").Append(" ").Append(_type.Name).Append(@" { - public sealed class ValueObjectJsonConverter : global::System.Text.Json.Serialization.JsonConverter<").Append(_type.TypeFullyQualified).Append(@"> + public sealed class ValueObjectJsonConverter : global::System.Text.Json.Serialization.JsonConverter<").AppendTypeFullyQualified(_type).Append(@"> {"); for (var i = 0; i < _assignableInstanceFieldsAndProperties.Count; i++) @@ -45,7 +45,7 @@ public sealed class ValueObjectJsonConverter : global::System.Text.Json.Serializ var memberInfo = _assignableInstanceFieldsAndProperties[i]; _sb.Append(@" - private readonly global::System.Text.Json.Serialization.JsonConverter<").Append(memberInfo.TypeFullyQualifiedWithNullability).Append("> _").Append(memberInfo.ArgumentName.Raw).Append(@"Converter; + private readonly global::System.Text.Json.Serialization.JsonConverter<").AppendTypeFullyQualified(memberInfo).Append("> _").Append(memberInfo.ArgumentName.Raw).Append(@"Converter; private readonly string _").Append(memberInfo.ArgumentName.Raw).Append("PropertyName;"); } @@ -66,7 +66,7 @@ public ValueObjectJsonConverter(global::System.Text.Json.JsonSerializerOptions o var memberInfo = _assignableInstanceFieldsAndProperties[i]; _sb.Append(@" - this._").Append(memberInfo.ArgumentName.Raw).Append("Converter = (global::System.Text.Json.Serialization.JsonConverter<").Append(memberInfo.TypeFullyQualifiedWithNullability).Append(">)global::Thinktecture.JsonSerializerOptionsExtensions.GetCustomValueObjectMemberConverter(options, typeof(").Append(memberInfo.TypeFullyQualified).Append(@")); + this._").Append(memberInfo.ArgumentName.Raw).Append("Converter = (global::System.Text.Json.Serialization.JsonConverter<").AppendTypeFullyQualified(memberInfo).Append(">)global::Thinktecture.JsonSerializerOptionsExtensions.GetCustomValueObjectMemberConverter(options, typeof(").AppendTypeFullyQualifiedWithoutNullAnnotation(memberInfo).Append(@")); this._").Append(memberInfo.ArgumentName.Raw).Append("PropertyName = namingPolicy?.ConvertName(\"").Append(memberInfo.Name).Append(@""") ?? """).Append(memberInfo.Name).Append(@""";"); } @@ -74,7 +74,7 @@ public ValueObjectJsonConverter(global::System.Text.Json.JsonSerializerOptions o } /// - public override ").Append(_type.TypeFullyQualifiedNullAnnotated).Append(@" Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + public override ").AppendTypeFullyQualifiedNullAnnotated(_type).Append(@" Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) { if (reader.TokenType == global::System.Text.Json.JsonTokenType.Null) return default; @@ -90,7 +90,7 @@ public ValueObjectJsonConverter(global::System.Text.Json.JsonSerializerOptions o var memberInfo = _assignableInstanceFieldsAndProperties[i]; _sb.Append(@" - ").Append(memberInfo.TypeFullyQualifiedNullAnnotated).Append(" ").Append(memberInfo.ArgumentName.Escaped).Append(" = default;"); + ").AppendTypeFullyQualifiedNullAnnotated(memberInfo).Append(" ").Append(memberInfo.ArgumentName.Escaped).Append(" = default;"); } _sb.Append(@" @@ -130,7 +130,7 @@ public ValueObjectJsonConverter(global::System.Text.Json.JsonSerializerOptions o _sb.Append("(comparer.Equals(propName, this._").Append(memberInfo.ArgumentName.Raw).Append(@"PropertyName)) { - ").Append(memberInfo.ArgumentName.Escaped).Append(" = this._").Append(memberInfo.ArgumentName.Raw).Append("Converter.Read(ref reader, typeof(").Append(memberInfo.TypeFullyQualified).Append(@"), options); + ").Append(memberInfo.ArgumentName.Escaped).Append(" = this._").Append(memberInfo.ArgumentName.Raw).Append("Converter.Read(ref reader, typeof(").AppendTypeFullyQualifiedWithoutNullAnnotation(memberInfo).Append(@"), options); }"); } @@ -146,7 +146,7 @@ public ValueObjectJsonConverter(global::System.Text.Json.JsonSerializerOptions o _sb.Append(@" } - var validationError = ").Append(_type.TypeFullyQualified).Append(".Validate("); + var validationError = ").AppendTypeFullyQualified(_type).Append(".Validate("); cancellationToken.ThrowIfCancellationRequested(); @@ -168,7 +168,7 @@ public ValueObjectJsonConverter(global::System.Text.Json.JsonSerializerOptions o } /// - public override void Write(global::System.Text.Json.Utf8JsonWriter writer, ").Append(_type.TypeFullyQualified).Append(@" value, global::System.Text.Json.JsonSerializerOptions options) + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, ").AppendTypeFullyQualified(_type).Append(@" value, global::System.Text.Json.JsonSerializerOptions options) { writer.WriteStartObject(); @@ -196,7 +196,7 @@ public override void Write(global::System.Text.Json.Utf8JsonWriter writer, ").Ap else { _sb.Append(@" - if(!ignoreDefaultValues || !").Append(memberInfo.ArgumentName.Raw).Append("PropertyValue.Equals(default(").Append(memberInfo.TypeFullyQualifiedWithNullability).Append(@"))) + if(!ignoreDefaultValues || !").Append(memberInfo.ArgumentName.Raw).Append("PropertyValue.Equals(default(").AppendTypeFullyQualified(memberInfo).Append(@"))) { "); } @@ -218,7 +218,7 @@ public class ValueObjectJsonConverterFactory : global::System.Text.Json.Serializ /// public override bool CanConvert(global::System.Type typeToConvert) { - return typeof(").Append(_type.TypeFullyQualified).Append(@").IsAssignableFrom(typeToConvert); + return typeof(").AppendTypeFullyQualified(_type).Append(@").IsAssignableFrom(typeToConvert); } /// diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectMessagePackCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectMessagePackCodeGenerator.cs index d6a591e2..bdad21a0 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectMessagePackCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectMessagePackCodeGenerator.cs @@ -37,10 +37,10 @@ namespace ").Append(_type.Namespace).Append(@"; [global::MessagePack.MessagePackFormatter(typeof(ValueObjectMessagePackFormatter))] partial ").Append(_type.IsReferenceType ? "class" : "struct").Append(" ").Append(_type.Name).Append(@" { - public sealed class ValueObjectMessagePackFormatter : global::MessagePack.Formatters.IMessagePackFormatter<").Append(_type.TypeFullyQualifiedNullAnnotated).Append(@"> + public sealed class ValueObjectMessagePackFormatter : global::MessagePack.Formatters.IMessagePackFormatter<").AppendTypeFullyQualifiedNullAnnotated(_type).Append(@"> { /// - public ").Append(_type.TypeFullyQualifiedNullAnnotated).Append(@" Deserialize(ref global::MessagePack.MessagePackReader reader, global::MessagePack.MessagePackSerializerOptions options) + public ").AppendTypeFullyQualifiedNullAnnotated(_type).Append(@" Deserialize(ref global::MessagePack.MessagePackReader reader, global::MessagePack.MessagePackSerializerOptions options) { if (reader.TryReadNil()) return default; @@ -71,7 +71,7 @@ public sealed class ValueObjectMessagePackFormatter : global::MessagePack.Format _sb.Append(@" - var validationError = ").Append(_type.TypeFullyQualified).Append(".Validate("); + var validationError = ").AppendTypeFullyQualified(_type).Append(".Validate("); cancellationToken.ThrowIfCancellationRequested(); @@ -98,7 +98,7 @@ public sealed class ValueObjectMessagePackFormatter : global::MessagePack.Format } /// - public void Serialize(ref global::MessagePack.MessagePackWriter writer, ").Append(_type.TypeFullyQualifiedNullAnnotated).Append(@" value, global::MessagePack.MessagePackSerializerOptions options) + public void Serialize(ref global::MessagePack.MessagePackWriter writer, ").AppendTypeFullyQualifiedNullAnnotated(_type).Append(@" value, global::MessagePack.MessagePackSerializerOptions options) {"); if (_type.IsReferenceType) @@ -164,7 +164,7 @@ private static void GenerateWriteValue(StringBuilder sb, InstanceMemberInfo memb return; } - sb.Append("global::MessagePack.FormatterResolverExtensions.GetFormatterWithVerify<").Append(memberInfo.TypeFullyQualifiedWithNullability).Append(">(resolver).Serialize(ref writer, value.").Append(memberInfo.Name).Append(", options)"); + sb.Append("global::MessagePack.FormatterResolverExtensions.GetFormatterWithVerify<").AppendTypeFullyQualified(memberInfo).Append(">(resolver).Serialize(ref writer, value.").Append(memberInfo.Name).Append(", options)"); } private static void GenerateReadValue(StringBuilder sb, InstanceMemberInfo memberInfo) @@ -201,6 +201,6 @@ private static void GenerateReadValue(StringBuilder sb, InstanceMemberInfo membe return; } - sb.Append("global::MessagePack.FormatterResolverExtensions.GetFormatterWithVerify<").Append(memberInfo.TypeFullyQualifiedWithNullability).Append(">(resolver).Deserialize(ref reader, options)"); + sb.Append("global::MessagePack.FormatterResolverExtensions.GetFormatterWithVerify<").AppendTypeFullyQualified(memberInfo).Append(">(resolver).Deserialize(ref reader, options)"); } } diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectNewtonsoftJsonCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectNewtonsoftJsonCodeGenerator.cs index 2845ddb5..24cfed9a 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectNewtonsoftJsonCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectNewtonsoftJsonCodeGenerator.cs @@ -39,7 +39,7 @@ namespace ").Append(_type.Namespace).Append(@"; { public sealed class ValueObjectNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter { - private static readonly global::System.Type _type = typeof(").Append(_type.TypeFullyQualified).Append(@"); + private static readonly global::System.Type _type = typeof(").AppendTypeFullyQualified(_type).Append(@"); /// public override bool CanConvert(global::System.Type objectType) @@ -60,7 +60,7 @@ public override bool CanConvert(global::System.Type objectType) if (objectType.IsClass || global::System.Nullable.GetUnderlyingType(objectType) == _type) return null; - return default(").Append(_type.TypeFullyQualified).Append(@"); + return default(").AppendTypeFullyQualified(_type).Append(@"); } if (reader.TokenType != global::Newtonsoft.Json.JsonToken.StartObject) @@ -81,7 +81,7 @@ public override bool CanConvert(global::System.Type objectType) var memberInfo = _assignableInstanceFieldsAndProperties[i]; _sb.Append(@" - ").Append(memberInfo.TypeFullyQualifiedNullAnnotated).Append(" ").Append(memberInfo.ArgumentName.Escaped).Append(" = default;"); + ").AppendTypeFullyQualifiedNullAnnotated(memberInfo).Append(" ").Append(memberInfo.ArgumentName.Escaped).Append(" = default;"); } _sb.Append(@" @@ -139,7 +139,7 @@ public override bool CanConvert(global::System.Type objectType) _sb.Append(@"(comparer.Equals(propName, """).Append(memberInfo.ArgumentName.Escaped).Append(@""")) { - ").Append(memberInfo.ArgumentName.Escaped).Append(" = serializer.Deserialize<").Append(memberInfo.TypeFullyQualifiedWithNullability).Append(@">(reader); + ").Append(memberInfo.ArgumentName.Escaped).Append(" = serializer.Deserialize<").AppendTypeFullyQualified(memberInfo).Append(@">(reader); }"); } @@ -162,7 +162,7 @@ public override bool CanConvert(global::System.Type objectType) _sb.Append(@" } - var validationError = ").Append(_type.TypeFullyQualified).Append(".Validate("); + var validationError = ").AppendTypeFullyQualified(_type).Append(".Validate("); cancellationToken.ThrowIfCancellationRequested(); @@ -201,7 +201,7 @@ public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object return; } - var obj = (").Append(_type.TypeFullyQualified).Append(@")value; + var obj = (").AppendTypeFullyQualified(_type).Append(@")value; var resolver = serializer.ContractResolver as global::Newtonsoft.Json.Serialization.DefaultContractResolver; writer.WriteStartObject();"); diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectSourceGeneratorState.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectSourceGeneratorState.cs index cdee60a5..c72b7436 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectSourceGeneratorState.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectSourceGeneratorState.cs @@ -3,14 +3,14 @@ namespace Thinktecture.CodeAnalysis.ValueObjects; public sealed class ComplexValueObjectSourceGeneratorState : ITypeInformation, IEquatable { public string TypeFullyQualified { get; } - public string TypeFullyQualifiedNullable { get; } - public string TypeFullyQualifiedNullAnnotated => IsReferenceType ? TypeFullyQualifiedNullable : TypeFullyQualified; public string TypeMinimallyQualified { get; } public bool IsEqualWithReferenceEquality => false; public string? Namespace { get; } public string Name { get; } public bool IsReferenceType { get; } + public NullableAnnotation NullableAnnotation { get; } + public bool IsNullableStruct { get; } public string? FactoryValidationReturnType { get; } @@ -31,10 +31,11 @@ public ComplexValueObjectSourceGeneratorState( Settings = settings; Name = type.Name; Namespace = type.ContainingNamespace?.IsGlobalNamespace == true ? null : type.ContainingNamespace?.ToString(); - TypeFullyQualified = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - TypeFullyQualifiedNullable = $"{TypeFullyQualified}?"; + TypeFullyQualified = type.ToFullyQualifiedDisplayString(); TypeMinimallyQualified = type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); IsReferenceType = type.IsReferenceType; + NullableAnnotation = type.NullableAnnotation; + IsNullableStruct = type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T; var nonIgnoredMembers = type.GetNonIgnoredMembers(); AssignableInstanceFieldsAndProperties = type.GetAssignableFieldsAndPropertiesAndCheckForReadOnly(nonIgnoredMembers, factory, true, true, cancellationToken).ToList(); @@ -45,12 +46,7 @@ public ComplexValueObjectSourceGeneratorState( : (nonIgnoredMembers.FirstOrDefault(m => m.IsStatic && m.Name == Constants.Methods.VALIDATE_FACTORY_ARGUMENTS && m is IMethodSymbol method && method.ReturnType.SpecialType != SpecialType.System_Void) as IMethodSymbol)?.ReturnType; if (factoryValidationReturnType is not null) - { - FactoryValidationReturnType = factoryValidationReturnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - - if (factoryValidationReturnType.NullableAnnotation == NullableAnnotation.Annotated) - FactoryValidationReturnType += "?"; - } + FactoryValidationReturnType = factoryValidationReturnType.ToFullyQualifiedDisplayString(); } private IReadOnlyList GetEqualityMembers() diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/DivisionOperatorsCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/DivisionOperatorsCodeGenerator.cs index 4280a247..0173e14d 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/DivisionOperatorsCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/DivisionOperatorsCodeGenerator.cs @@ -54,13 +54,13 @@ public void GenerateBaseTypes(StringBuilder sb, InterfaceCodeGeneratorState stat return; sb.Append(@" - global::System.Numerics.IDivisionOperators<").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.Type.TypeFullyQualified).Append(">"); + global::System.Numerics.IDivisionOperators<").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.Type).Append(">"); if (!_withKeyTypeOverloads) return; sb.Append(@", - global::System.Numerics.IDivisionOperators<").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.KeyMember.TypeFullyQualified).Append(", ").Append(state.Type.TypeFullyQualified).Append(">"); + global::System.Numerics.IDivisionOperators<").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.KeyMember).Append(", ").AppendTypeFullyQualified(state.Type).Append(">"); } public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState state) @@ -73,7 +73,7 @@ public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState { sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator /(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator /(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(typeLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(" / right.").Append(state.KeyMember.Name).Append(@")); }"); @@ -84,7 +84,7 @@ public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator checked /(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator checked /(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(typeLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(checked(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(" / right.").Append(state.KeyMember.Name).Append(@"))); }"); @@ -109,13 +109,13 @@ private void GenerateOverloadsForKeyType( sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator /(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator /(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(@" / right)); } /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator /(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator /(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left / right.").Append(state.KeyMember.Name).Append(@")); }"); @@ -126,13 +126,13 @@ private void GenerateOverloadsForKeyType( sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator checked /(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator checked /(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(checked(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(@" / right))); } /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator checked /(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator checked /(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(checked(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left / right.").Append(state.KeyMember.Name).Append(@"))); }"); diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/KeyedValueObjectCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/KeyedValueObjectCodeGenerator.cs index be8b176c..a0df0438 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/KeyedValueObjectCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/KeyedValueObjectCodeGenerator.cs @@ -53,18 +53,18 @@ private void GenerateValueObject(CancellationToken cancellationToken) if (_state is { Settings.SkipFactoryMethods: false }) { _sb.Append(@" - [global::System.ComponentModel.TypeConverter(typeof(global::Thinktecture.ValueObjectTypeConverter<").Append(_state.TypeFullyQualified).Append(", ").Append(_state.KeyMember.TypeFullyQualified).Append(", ").Append(_state.ValidationError.TypeFullyQualified).Append(">))]"); + [global::System.ComponentModel.TypeConverter(typeof(global::Thinktecture.ValueObjectTypeConverter<").AppendTypeFullyQualified(_state).Append(", ").AppendTypeFullyQualified(_state.KeyMember).Append(", ").AppendTypeFullyQualified(_state.ValidationError).Append(">))]"); } _sb.Append(@" - partial ").Append(_state.IsReferenceType ? "class" : "struct").Append(" ").Append(_state.Name).Append(" : global::System.IEquatable<").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@">, - global::Thinktecture.IKeyedValueObject<").Append(_state.KeyMember.TypeFullyQualified).Append(@">, - global::Thinktecture.IValueObjectConvertable<").Append(_state.KeyMember.TypeFullyQualified).Append(">"); + partial ").Append(_state.IsReferenceType ? "class" : "struct").Append(" ").Append(_state.Name).Append(" : global::System.IEquatable<").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@">, + global::Thinktecture.IKeyedValueObject<").AppendTypeFullyQualified(_state.KeyMember).Append(@">, + global::Thinktecture.IValueObjectConvertable<").AppendTypeFullyQualified(_state.KeyMember).Append(">"); if (!_state.Settings.SkipFactoryMethods) { _sb.Append(@", - global::Thinktecture.IValueObjectFactory<").Append(_state.TypeFullyQualified).Append(", ").Append(_state.KeyMember.TypeFullyQualified).Append(", ").Append(_state.ValidationError.TypeFullyQualified).Append(">"); + global::Thinktecture.IValueObjectFactory<").AppendTypeFullyQualified(_state).Append(", ").AppendTypeFullyQualified(_state.KeyMember).Append(", ").AppendTypeFullyQualified(_state.ValidationError).Append(">"); } foreach (var desiredFactory in _state.Settings.DesiredFactories) @@ -73,12 +73,12 @@ private void GenerateValueObject(CancellationToken cancellationToken) continue; _sb.Append(@", - global::Thinktecture.IValueObjectFactory<").Append(_state.TypeFullyQualified).Append(", ").Append(desiredFactory.TypeFullyQualified).Append(", ").Append(_state.ValidationError.TypeFullyQualified).Append(">"); + global::Thinktecture.IValueObjectFactory<").AppendTypeFullyQualified(_state).Append(", ").AppendTypeFullyQualified(desiredFactory).Append(", ").AppendTypeFullyQualified(_state.ValidationError).Append(">"); if (desiredFactory.UseForSerialization != SerializationFrameworks.None) { _sb.Append(@", - global::Thinktecture.IValueObjectConvertable<").Append(desiredFactory.TypeFullyQualified).Append(">"); + global::Thinktecture.IValueObjectConvertable<").AppendTypeFullyQualified(desiredFactory).Append(">"); } } @@ -88,13 +88,13 @@ private void GenerateValueObject(CancellationToken cancellationToken) GenerateModuleInitializerForKeyedValueObject(emptyStringYieldsNull); _sb.Append(@" - private static readonly int _typeHashCode = typeof(").Append(_state.TypeFullyQualified).Append(").GetHashCode();"); + private static readonly int _typeHashCode = typeof(").AppendTypeFullyQualified(_state).Append(").GetHashCode();"); if (!_state.IsReferenceType) { _sb.Append(@" - public static readonly ").Append(_state.TypeFullyQualified).Append(" ").Append(_state.Settings.DefaultInstancePropertyName).Append(" = default;"); + public static readonly ").AppendTypeFullyQualified(_state).Append(" ").Append(_state.Settings.DefaultInstancePropertyName).Append(" = default;"); } if (!_state.Settings.SkipKeyMember) @@ -142,7 +142,7 @@ private void GenerateToValue() /// Gets the identifier of the item. /// [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] - ").Append(_state.KeyMember.TypeFullyQualified).Append(" global::Thinktecture.IValueObjectConvertable<").Append(_state.KeyMember.TypeFullyQualified).Append(@">.ToValue() + ").AppendTypeFullyQualified(_state.KeyMember).Append(" global::Thinktecture.IValueObjectConvertable<").AppendTypeFullyQualified(_state.KeyMember).Append(@">.ToValue() { return this.").Append(_state.KeyMember.Name).Append(@"; }"); @@ -151,15 +151,12 @@ private void GenerateToValue() private void GenerateModuleInitializerForKeyedValueObject(bool emptyStringYieldsNull) { var keyMember = _state.KeyMember; - var typeFullyQualified = _state.TypeFullyQualified; - var nullAnnotatedTypeFullyQualified = emptyStringYieldsNull ? _state.TypeFullyQualifiedNullAnnotated : typeFullyQualified; - var keyMemberWithoutNullAnnotation = keyMember.IsReferenceType ? keyMember.TypeFullyQualified : keyMember.TypeFullyQualifiedWithNullability; _sb.Append(@" [global::System.Runtime.CompilerServices.ModuleInitializer] internal static void ModuleInit() { - global::System.Func<").Append(keyMember.TypeFullyQualifiedWithNullability).Append(", ").Append(nullAnnotatedTypeFullyQualified).Append(">").Append(_state.Settings.SkipFactoryMethods ? "?" : null).Append(" convertFromKey = "); + global::System.Func<").AppendTypeFullyQualified(keyMember).Append(", ").AppendTypeFullyQualified(_state, nullable: emptyStringYieldsNull).Append(">").Append(_state.Settings.SkipFactoryMethods ? "?" : null).Append(" convertFromKey = "); if (_state.Settings.SkipFactoryMethods) { @@ -167,11 +164,11 @@ internal static void ModuleInit() } else { - _sb.Append("new (").Append(typeFullyQualified).Append(".").Append(_state.Settings.CreateFactoryMethodName).Append(")"); + _sb.Append("new (").AppendTypeFullyQualified(_state).Append(".").Append(_state.Settings.CreateFactoryMethodName).Append(")"); } _sb.Append(@"; - global::System.Linq.Expressions.Expression>").Append(_state.Settings.SkipFactoryMethods ? "?" : null).Append(" convertFromKeyExpression = "); + global::System.Linq.Expressions.Expression>").Append(_state.Settings.SkipFactoryMethods ? "?" : null).Append(" convertFromKeyExpression = "); if (_state.Settings.SkipFactoryMethods) { @@ -179,17 +176,17 @@ internal static void ModuleInit() } else { - _sb.Append("static ").Append(keyMember.ArgumentName.Escaped).Append(" => ").Append(typeFullyQualified).Append(".").Append(_state.Settings.CreateFactoryMethodName).Append("(").Append(keyMember.ArgumentName.Escaped).Append(")"); + _sb.Append("static ").Append(keyMember.ArgumentName.Escaped).Append(" => ").AppendTypeFullyQualified(_state).Append(".").Append(_state.Settings.CreateFactoryMethodName).Append("(").Append(keyMember.ArgumentName.Escaped).Append(")"); } _sb.Append(@"; - global::System.Linq.Expressions.Expression> convertFromKeyExpressionViaCtor = static ").Append(keyMember.ArgumentName.Escaped).Append(" => new ").Append(typeFullyQualified).Append("(").Append(keyMember.ArgumentName.Escaped).Append(@"); + global::System.Linq.Expressions.Expression> convertFromKeyExpressionViaCtor = static ").Append(keyMember.ArgumentName.Escaped).Append(" => new ").AppendTypeFullyQualified(_state).Append("(").Append(keyMember.ArgumentName.Escaped).Append(@"); - var convertToKey = new global::System.Func<").Append(typeFullyQualified).Append(", ").Append(keyMember.TypeFullyQualifiedWithNullability).Append(">(static item => item.").Append(keyMember.Name).Append(@"); - global::System.Linq.Expressions.Expression> convertToKeyExpression = static obj => obj.").Append(keyMember.Name).Append(@"; + var convertToKey = new global::System.Func<").AppendTypeFullyQualified(_state).Append(", ").AppendTypeFullyQualified(keyMember).Append(">(static item => item.").Append(keyMember.Name).Append(@"); + global::System.Linq.Expressions.Expression> convertToKeyExpression = static obj => obj.").Append(keyMember.Name).Append(@"; - var type = typeof(").Append(typeFullyQualified).Append(@"); - var metadata = new global::Thinktecture.Internal.KeyedValueObjectMetadata(type, typeof(").Append(keyMemberWithoutNullAnnotation).Append(@"), false, false, convertFromKey, convertFromKeyExpression, convertFromKeyExpressionViaCtor, convertToKey, convertToKeyExpression); + var type = typeof(").AppendTypeFullyQualified(_state).Append(@"); + var metadata = new global::Thinktecture.Internal.KeyedValueObjectMetadata(type, typeof(").AppendTypeFullyQualified(keyMember).Append(@"), false, false, convertFromKey, convertFromKeyExpression, convertFromKeyExpressionViaCtor, convertToKey, convertToKeyExpression); global::Thinktecture.Internal.KeyedValueObjectMetadataLookup.AddMetadata(type, metadata); } @@ -203,12 +200,12 @@ private void GenerateImplicitConversionToKey() _sb.Append(@" /// - /// Implicit conversion to the type . + /// Implicit conversion to the type . /// /// Object to covert. /// The of provided or default if is null. [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""obj"")] - public static implicit operator ").Append(keyMember.TypeFullyQualifiedNullable).Append("(").Append(_state.IsReferenceType ? _state.TypeFullyQualifiedNullAnnotated : _state.TypeFullyQualifiedNullable).Append(@" obj) + public static implicit operator ").AppendTypeFullyQualifiedNullable(keyMember).Append("(").AppendTypeFullyQualifiedNullable(_state).Append(@" obj) { return obj?.").Append(keyMember.Name).Append(@"; }"); @@ -221,11 +218,11 @@ private void GenerateImplicitConversionToKey() _sb.Append(@" /// - /// Implicit conversion to the type . + /// Implicit conversion to the type . /// /// Object to covert. /// The of provided . - public static implicit operator ").Append(keyMember.TypeFullyQualified).Append("(").Append(_state.TypeFullyQualified).Append(@" obj) + public static implicit operator ").AppendTypeFullyQualified(keyMember).Append("(").AppendTypeFullyQualified(_state).Append(@" obj) { return obj.").Append(keyMember.Name).Append(@"; }"); @@ -241,12 +238,12 @@ private void GenerateExplicitConversionToKey() _sb.Append(@" /// - /// Explicit conversion to the type . + /// Explicit conversion to the type . /// /// Object to covert. /// The of provided or default if is null. [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""obj"")] - public static explicit operator ").Append(keyMember.TypeFullyQualifiedWithNullability).Append("(").Append(_state.TypeFullyQualified).Append(@" obj) + public static explicit operator ").AppendTypeFullyQualified(keyMember).Append("(").AppendTypeFullyQualified(_state).Append(@" obj) { if(obj is null) throw new global::System.NullReferenceException(); @@ -264,7 +261,7 @@ private void GenerateExplicitConversion(bool emptyStringYieldsNull) _sb.Append(@" /// - /// Explicit conversion from the type . + /// Explicit conversion from the type . /// /// Value to covert. /// An instance of ."); @@ -276,7 +273,7 @@ private void GenerateExplicitConversion(bool emptyStringYieldsNull) } _sb.Append(@" - public static explicit operator ").Append(_state.TypeFullyQualified).Append(nullableQuestionMark).Append("(").Append(keyMember.TypeFullyQualified).Append(nullableQuestionMark).Append(" ").Append(keyMember.ArgumentName.Escaped).Append(@") + public static explicit operator ").AppendTypeFullyQualified(_state).Append(nullableQuestionMark).Append("(").AppendTypeFullyQualified(keyMember).Append(nullableQuestionMark).Append(" ").Append(keyMember.ArgumentName.Escaped).Append(@") {"); if (bothAreReferenceTypes) @@ -288,7 +285,7 @@ private void GenerateExplicitConversion(bool emptyStringYieldsNull) } _sb.Append(@" - return ").Append(_state.TypeFullyQualified).Append(".").Append(_state.Settings.CreateFactoryMethodName).Append("(").Append(keyMember.ArgumentName.Escaped).Append(@"); + return ").AppendTypeFullyQualified(_state).Append(".").Append(_state.Settings.CreateFactoryMethodName).Append("(").Append(keyMember.ArgumentName.Escaped).Append(@"); }"); } @@ -306,9 +303,9 @@ private void GenerateCreateMethod(bool allowNullOutput, bool emptyStringYieldsNu } _sb.Append(@" - public static ").Append(_state.TypeFullyQualified).Append(allowNullOutput ? "?" : null).Append(" ").Append(_state.Settings.CreateFactoryMethodName).Append("(").RenderArgumentWithType(_state.KeyMember, useNullableTypes: allowNullOutput).Append(@") + public static ").AppendTypeFullyQualified(_state).Append(allowNullOutput ? "?" : null).Append(" ").Append(_state.Settings.CreateFactoryMethodName).Append("(").RenderArgumentWithType(_state.KeyMember, useNullableTypes: allowNullOutput).Append(@") { - var validationError = Validate(").RenderArgument(_state.KeyMember).Append(", null, ").Append("out ").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" obj); + var validationError = Validate(").RenderArgument(_state.KeyMember).Append(", null, ").Append("out ").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" obj); if (validationError is not null) throw new global::System.ComponentModel.DataAnnotations.ValidationException(validationError.ToString() ?? ""Validation failed.""); @@ -321,7 +318,7 @@ private void GenerateTryCreateMethod(bool allowNullOutput, bool emptyStringYield { _sb.Append(@" - public static bool ").Append(_state.Settings.TryCreateFactoryMethodName).Append("(").RenderArgumentWithType(_state.KeyMember, useNullableTypes: allowNullOutput).Append(emptyStringYieldsNull ? "," : ", [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]").Append(" out ").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" obj) + public static bool ").Append(_state.Settings.TryCreateFactoryMethodName).Append("(").RenderArgumentWithType(_state.KeyMember, useNullableTypes: allowNullOutput).Append(emptyStringYieldsNull ? "," : ", [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]").Append(" out ").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" obj) { return ").Append(_state.Settings.TryCreateFactoryMethodName).Append("(").RenderArgument(_state.KeyMember).Append(@", out obj, out _); }"); @@ -330,8 +327,8 @@ private void GenerateTryCreateMethod(bool allowNullOutput, bool emptyStringYield public static bool ").Append(_state.Settings.TryCreateFactoryMethodName).Append(@"( ").RenderArgumentWithType(_state.KeyMember, useNullableTypes: allowNullOutput).Append(@", - ").Append(emptyStringYieldsNull ? null : "[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] ").Append("out ").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" obj, - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(false)] out ").Append(_state.ValidationError.TypeFullyQualified).Append(@"? validationError) + ").Append(emptyStringYieldsNull ? null : "[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] ").Append("out ").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" obj, + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(false)] out ").AppendTypeFullyQualified(_state.ValidationError).Append(@"? validationError) { validationError = Validate(").RenderArgument(_state.KeyMember).Append(@", null, out obj); @@ -345,7 +342,7 @@ private void GenerateValidateMethod(bool allowNullKeyMemberInput, bool allowNull _sb.Append(@" - public static ").Append(_state.ValidationError.TypeFullyQualified).Append("? Validate(").RenderArgumentWithType(_state.KeyMember, useNullableTypes: allowNullKeyMemberInput).Append(", global::System.IFormatProvider? ").Append(providerArgumentName).Append(", out ").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" obj) + public static ").AppendTypeFullyQualified(_state.ValidationError).Append("? Validate(").RenderArgumentWithType(_state.KeyMember, useNullableTypes: allowNullKeyMemberInput).Append(", global::System.IFormatProvider? ").Append(providerArgumentName).Append(", out ").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" obj) {"); if (emptyStringYieldsNull) @@ -374,13 +371,13 @@ private void GenerateValidateMethod(bool allowNullKeyMemberInput, bool allowNull if(").Append(_state.KeyMember.ArgumentName.Escaped).Append(@" is null) { obj = default; - return global::Thinktecture.Internal.ValidationErrorCreator.CreateValidationError<").Append(_state.ValidationError.TypeFullyQualified).Append(@">(""The argument '").Append(_state.KeyMember.ArgumentName.Escaped).Append(@"' must not be null.""); + return global::Thinktecture.Internal.ValidationErrorCreator.CreateValidationError<").AppendTypeFullyQualified(_state.ValidationError).Append(@">(""The argument '").Append(_state.KeyMember.ArgumentName.Escaped).Append(@"' must not be null.""); } "); } _sb.Append(@" - ").Append(_state.ValidationError.TypeFullyQualified).Append(@"? validationError = null; + ").AppendTypeFullyQualified(_state.ValidationError).Append(@"? validationError = null; "); if (_state.FactoryValidationReturnType is not null) @@ -420,7 +417,7 @@ private void GenerateValidateFactoryArguments() if (_state.FactoryValidationReturnType is not null) _sb.Append("private "); - _sb.Append("static partial ").Append(_state.FactoryValidationReturnType ?? "void").Append(" ").Append(Constants.Methods.VALIDATE_FACTORY_ARGUMENTS).Append("(ref ").Append(_state.ValidationError.TypeFullyQualified).Append("? validationError, ").RenderArgumentWithType(_state.KeyMember, "ref ", addAllowNullNotNullCombi: true).Append(");"); + _sb.Append("static partial ").Append(_state.FactoryValidationReturnType ?? "void").Append(" ").Append(Constants.Methods.VALIDATE_FACTORY_ARGUMENTS).Append("(ref ").AppendTypeFullyQualified(_state.ValidationError).Append("? validationError, ").RenderArgumentWithType(_state.KeyMember, "ref ", addAllowNullNotNullCombi: true).Append(");"); } private void GenerateFactoryPostInit() @@ -437,7 +434,7 @@ private void GenerateFactoryPostInit() private void GenerateConstructCall() { - _sb.Append("new ").Append(_state.TypeFullyQualified).Append("(").RenderArgument(_state.KeyMember).Append(")"); + _sb.Append("new ").AppendTypeFullyQualified(_state).Append("(").RenderArgument(_state.KeyMember).Append(")"); } private void GenerateConstructor() @@ -461,11 +458,11 @@ private void GenerateEquals() /// public override bool Equals(object? other) { - return other is ").Append(_state.TypeFullyQualified).Append(@" obj && Equals(obj); + return other is ").AppendTypeFullyQualified(_state).Append(@" obj && Equals(obj); } /// - public bool Equals(").Append(_state.TypeFullyQualifiedNullAnnotated).Append(@" other) + public bool Equals(").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" other) {"); if (_state.IsReferenceType) diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/KeyedValueObjectSourceGeneratorState.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/KeyedValueObjectSourceGeneratorState.cs index 61b4ce40..7be65e8f 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/KeyedValueObjectSourceGeneratorState.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/KeyedValueObjectSourceGeneratorState.cs @@ -3,14 +3,14 @@ namespace Thinktecture.CodeAnalysis.ValueObjects; public sealed class KeyedValueObjectSourceGeneratorState : ITypeInformation, IEquatable { public string TypeFullyQualified { get; } - public string TypeFullyQualifiedNullable { get; } - public string TypeFullyQualifiedNullAnnotated => IsReferenceType ? TypeFullyQualifiedNullable : TypeFullyQualified; public string TypeMinimallyQualified { get; } public bool IsEqualWithReferenceEquality => false; public string? Namespace { get; } public string Name { get; } public bool IsReferenceType { get; } + public NullableAnnotation NullableAnnotation { get; } + public bool IsNullableStruct { get; } public string? FactoryValidationReturnType { get; } @@ -29,10 +29,11 @@ public KeyedValueObjectSourceGeneratorState( Settings = settings; Name = type.Name; Namespace = type.ContainingNamespace?.IsGlobalNamespace == true ? null : type.ContainingNamespace?.ToString(); - TypeFullyQualified = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - TypeFullyQualifiedNullable = $"{TypeFullyQualified}?"; + TypeFullyQualified = type.ToFullyQualifiedDisplayString(); TypeMinimallyQualified = type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); IsReferenceType = type.IsReferenceType; + NullableAnnotation = type.NullableAnnotation; + IsNullableStruct = type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T; var nonIgnoredMembers = type.GetNonIgnoredMembers(); @@ -41,12 +42,7 @@ public KeyedValueObjectSourceGeneratorState( var member = nonIgnoredMembers[i]; if (member.IsValidateFactoryArgumentsImplementation(out var method) && method.ReturnType.SpecialType != SpecialType.System_Void) - { - FactoryValidationReturnType = method.ReturnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - - if (method.ReturnType.NullableAnnotation == NullableAnnotation.Annotated) - FactoryValidationReturnType += "?"; - } + FactoryValidationReturnType = method.ReturnType.ToFullyQualifiedDisplayString(); } } diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/MultiplyOperatorsCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/MultiplyOperatorsCodeGenerator.cs index 9e6ed0e5..1487229a 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/MultiplyOperatorsCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/MultiplyOperatorsCodeGenerator.cs @@ -54,13 +54,13 @@ public void GenerateBaseTypes(StringBuilder sb, InterfaceCodeGeneratorState stat return; sb.Append(@" - global::System.Numerics.IMultiplyOperators<").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.Type.TypeFullyQualified).Append(">"); + global::System.Numerics.IMultiplyOperators<").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.Type).Append(">"); if (!_withKeyTypeOverloads) return; sb.Append(@", - global::System.Numerics.IMultiplyOperators<").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.KeyMember.TypeFullyQualified).Append(", ").Append(state.Type.TypeFullyQualified).Append(">"); + global::System.Numerics.IMultiplyOperators<").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.KeyMember).Append(", ").AppendTypeFullyQualified(state.Type).Append(">"); } public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState state) @@ -73,7 +73,7 @@ public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState { sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator *(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator *(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(typeLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(" * right.").Append(state.KeyMember.Name).Append(@")); }"); @@ -84,7 +84,7 @@ public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator checked *(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator checked *(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(typeLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(checked(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(" * right.").Append(state.KeyMember.Name).Append(@"))); }"); @@ -109,13 +109,13 @@ private void GenerateOverloadsForKeyType( sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator *(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator *(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(@" * right)); } /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator *(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator *(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left * right.").Append(state.KeyMember.Name).Append(@")); }"); @@ -126,13 +126,13 @@ private void GenerateOverloadsForKeyType( sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator checked *(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator checked *(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(checked(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(@" * right))); } /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator checked *(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator checked *(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(checked(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left * right.").Append(state.KeyMember.Name).Append(@"))); }"); diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/SubtractionOperatorsCodeGenerator.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/SubtractionOperatorsCodeGenerator.cs index 74c9ae8f..6466e556 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/SubtractionOperatorsCodeGenerator.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/SubtractionOperatorsCodeGenerator.cs @@ -57,13 +57,13 @@ public void GenerateBaseTypes(StringBuilder sb, InterfaceCodeGeneratorState stat return; sb.Append(@" - global::System.Numerics.ISubtractionOperators<").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.Type.TypeFullyQualified).Append(">"); + global::System.Numerics.ISubtractionOperators<").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.Type).Append(">"); if (!_withKeyTypeOverloads) return; sb.Append(@", - global::System.Numerics.ISubtractionOperators<").Append(state.Type.TypeFullyQualified).Append(", ").Append(state.KeyMember.TypeFullyQualified).Append(", ").Append(state.Type.TypeFullyQualified).Append(">"); + global::System.Numerics.ISubtractionOperators<").AppendTypeFullyQualified(state.Type).Append(", ").AppendTypeFullyQualified(state.KeyMember).Append(", ").AppendTypeFullyQualified(state.Type).Append(">"); } public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState state) @@ -76,7 +76,7 @@ public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState { sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator -(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator -(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(typeLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(" - right.").Append(state.KeyMember.Name).Append(@")); }"); @@ -87,7 +87,7 @@ public void GenerateImplementation(StringBuilder sb, InterfaceCodeGeneratorState sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator checked -(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator checked -(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(typeLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(checked(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(" - right.").Append(state.KeyMember.Name).Append(@"))); }"); @@ -112,13 +112,13 @@ private void GenerateOverloadsForKeyType( sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator -(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator -(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(@" - right)); } /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator -(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator -(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left - right.").Append(state.KeyMember.Name).Append(@")); }"); @@ -129,13 +129,13 @@ private void GenerateOverloadsForKeyType( sb.Append(@" /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator checked -(").Append(state.Type.TypeFullyQualified).Append(" left, ").Append(state.KeyMember.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator checked -(").AppendTypeFullyQualified(state.Type).Append(" left, ").AppendTypeFullyQualified(state.KeyMember).Append(@" right) { ").Append(typeLeftNullCheck).Append(memberRightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(checked(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left.").Append(state.KeyMember.Name).Append(@" - right))); } /// - public static ").Append(state.Type.TypeFullyQualified).Append(" operator checked -(").Append(state.KeyMember.TypeFullyQualified).Append(" left, ").Append(state.Type.TypeFullyQualified).Append(@" right) + public static ").AppendTypeFullyQualified(state.Type).Append(" operator checked -(").AppendTypeFullyQualified(state.KeyMember).Append(" left, ").AppendTypeFullyQualified(state.Type).Append(@" right) { ").Append(memberLeftNullCheck).Append(typeLightNullCheck).Append("return ").Append(state.CreateFactoryMethodName).Append("(checked(").AppendCast(state.KeyMember, needsCastToResultType).Append("(left - right.").Append(state.KeyMember.Name).Append(@"))); }"); diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ValueObjectMemberSettings.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ValueObjectMemberSettings.cs index 4ff297b5..2900091b 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ValueObjectMemberSettings.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ValueObjectMemberSettings.cs @@ -43,7 +43,7 @@ public static ValueObjectMemberSettings Create(ISymbol member, ITypeSymbol type, return None; var equalityComparerGenericTypes = equalityComparerAttr.GetComparerTypes(); - var equalityComparerAccessorType = equalityComparerGenericTypes?.ComparerType?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + var equalityComparerAccessorType = equalityComparerGenericTypes?.ComparerType?.ToFullyQualifiedDisplayString(); var hasInvalidEqualityComparerType = equalityComparerGenericTypes is not null && !SymbolEqualityComparer.Default.Equals(equalityComparerGenericTypes.Value.ItemType, type); return new ValueObjectMemberSettings(true, diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/Extensions/StringBuilderExtensions.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/Extensions/StringBuilderExtensions.cs index 8e23def1..025034de 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/Extensions/StringBuilderExtensions.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/Extensions/StringBuilderExtensions.cs @@ -102,7 +102,7 @@ public static StringBuilder RenderArgumentWithType( if (addAllowNullNotNullCombi && member.IsReferenceType && member.NullableAnnotation != NullableAnnotation.Annotated) sb.Append("[global::System.Diagnostics.CodeAnalysis.AllowNullAttribute, global::System.Diagnostics.CodeAnalysis.NotNullAttribute] "); - sb.Append(prefix).Append(member.TypeFullyQualifiedWithNullability); + sb.Append(prefix).AppendTypeFullyQualified(member); if (useNullableTypes && !member.IsNullableStruct) sb.Append("?"); @@ -120,4 +120,57 @@ public static StringBuilder AppendCast( return sb; } + + public static StringBuilder AppendTypeFullyQualified( + this StringBuilder sb, + ITypeFullyQualified type) + { + return sb.Append(type.TypeFullyQualified); + } + + public static StringBuilder AppendTypeFullyQualified( + this StringBuilder sb, + ITypeInformationWithNullability type, + bool nullable) + { + return nullable + ? sb.AppendTypeFullyQualifiedNullable(type) + : sb.AppendTypeFullyQualified(type); + } + + public static StringBuilder AppendTypeFullyQualifiedWithoutNullAnnotation( + this StringBuilder sb, + ITypeInformationWithNullability type) + { + sb.AppendTypeFullyQualified(type); + + if (type is { IsReferenceType: true, NullableAnnotation: NullableAnnotation.Annotated }) + sb.Length -= 1; + + return sb; + } + + public static StringBuilder AppendTypeFullyQualifiedNullAnnotated( + this StringBuilder sb, + ITypeInformationWithNullability type) + { + sb.Append(type.TypeFullyQualified); + + if (type.IsReferenceType && type.NullableAnnotation != NullableAnnotation.Annotated) + sb.Append("?"); + + return sb; + } + + public static StringBuilder AppendTypeFullyQualifiedNullable( + this StringBuilder sb, + ITypeInformationWithNullability type) + { + sb.Append(type.TypeFullyQualified); + + if ((type.IsReferenceType && type.NullableAnnotation != NullableAnnotation.Annotated) || type is { IsReferenceType: false, IsNullableStruct: false }) + sb.Append("?"); + + return sb; + } } diff --git a/src/Thinktecture.Runtime.Extensions.SourceGenerator/Extensions/TypeSymbolExtensions.cs b/src/Thinktecture.Runtime.Extensions.SourceGenerator/Extensions/TypeSymbolExtensions.cs index 7cb9db5d..256f3f1a 100644 --- a/src/Thinktecture.Runtime.Extensions.SourceGenerator/Extensions/TypeSymbolExtensions.cs +++ b/src/Thinktecture.Runtime.Extensions.SourceGenerator/Extensions/TypeSymbolExtensions.cs @@ -8,6 +8,14 @@ namespace Thinktecture; public static class TypeSymbolExtensions { + private static readonly SymbolDisplayFormat _fullyQualifiedDisplayFormat = SymbolDisplayFormat.FullyQualifiedFormat + .AddMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier); + + public static string ToFullyQualifiedDisplayString(this ITypeSymbol type) + { + return type.ToDisplayString(_fullyQualifiedDisplayFormat); + } + public static bool IsNullOrObject([NotNullWhen(false)] this ITypeSymbol? type) { return type is null || type.SpecialType == SpecialType.System_Object; @@ -567,7 +575,7 @@ public static bool HasCreateInvalidItemImplementation( reportDiagnostic?.ReportDiagnostic(Diagnostic.Create(DiagnosticsDescriptors.InvalidSignatureOfCreateInvalidItem, method.GetIdentifier(cancellationToken).GetLocation(), enumType.Name, - keyType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))); + keyType.ToFullyQualifiedDisplayString())); return true; } diff --git a/test/Thinktecture.Runtime.Extensions.SourceGenerator.Tests/SourceGeneratorTests/EnumSourceGeneratorTests.cs b/test/Thinktecture.Runtime.Extensions.SourceGenerator.Tests/SourceGeneratorTests/EnumSourceGeneratorTests.cs index af567ab5..73d1fbc5 100644 --- a/test/Thinktecture.Runtime.Extensions.SourceGenerator.Tests/SourceGeneratorTests/EnumSourceGeneratorTests.cs +++ b/test/Thinktecture.Runtime.Extensions.SourceGenerator.Tests/SourceGeneratorTests/EnumSourceGeneratorTests.cs @@ -451,7 +451,6 @@ private TestEnum(int key) /// The identifier to return an enumeration item for. /// An instance of if is not null; otherwise null. /// If there is no item with the provided . - [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("key")] public static global::Thinktecture.Tests.TestEnum Get(int key) { if (!_itemsLookup.Value.TryGetValue(key, out var item)) @@ -4676,7 +4675,6 @@ private TestEnum(string key, bool isValid) /// /// The identifier to return an enumeration item for. /// An instance of if is not null; otherwise null. - [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("key")] public static global::Thinktecture.Tests.TestEnum Get(string? key) { if (key is null) @@ -5856,7 +5854,6 @@ private TestEnum(int key) /// The identifier to return an enumeration item for. /// An instance of if is not null; otherwise null. /// If there is no item with the provided . - [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("key")] public static global::Thinktecture.Tests.TestEnum Get(int key) { if (!_itemsLookup.Value.TryGetValue(key, out var item)) @@ -6205,7 +6202,6 @@ private TestEnum(int key) /// The identifier to return an enumeration item for. /// An instance of if is not null; otherwise null. /// If there is no item with the provided . - [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("key")] public static global::Thinktecture.Tests.TestEnum Get(int key) { if (!_itemsLookup.Value.TryGetValue(key, out var item)) @@ -6510,4 +6506,363 @@ internal static void DerivedTypesModuleInit() """); } + + [Fact] + public void Should_take_over_nullability_of_generic_members() + { + var source = """ + using System; + + namespace Thinktecture.Tests + { + [SmartEnum] + public abstract partial class TestEnum + { + public static readonly TestEnum Item1 = null!; + public static readonly TestEnum Item2 = null!; + + public Func?>? Prop1 { get; } + } + } + """; + var outputs = GetGeneratedOutputs(source, typeof(IEnum<>).Assembly); + outputs.Should().HaveCount(5); + + var mainOutput = outputs.Single(kvp => kvp.Key.Contains("Thinktecture.Tests.TestEnum.g.cs")).Value; + var comparableOutput = outputs.Single(kvp => kvp.Key.Contains("Thinktecture.Tests.TestEnum.Comparable.g.cs")).Value; + var parsableOutput = outputs.Single(kvp => kvp.Key.Contains("Thinktecture.Tests.TestEnum.Parsable.g.cs")).Value; + var comparisonOperatorsOutput = outputs.Single(kvp => kvp.Key.Contains("Thinktecture.Tests.TestEnum.ComparisonOperators.g.cs")).Value; + var equalityComparisonOperators = outputs.Single(kvp => kvp.Key.Contains("Thinktecture.Tests.TestEnum.EqualityComparisonOperators.g.cs")).Value; + + AssertOutput(mainOutput, _GENERATED_HEADER + """ + + namespace Thinktecture.Tests + { + [global::System.ComponentModel.TypeConverter(typeof(global::Thinktecture.ValueObjectTypeConverter))] + partial class TestEnum : global::Thinktecture.IEnum, + global::System.IEquatable + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void ModuleInit() + { + var convertFromKey = new global::System.Func(global::Thinktecture.Tests.TestEnum.Get); + global::System.Linq.Expressions.Expression> convertFromKeyExpression = static key => global::Thinktecture.Tests.TestEnum.Get(key); + + var convertToKey = new global::System.Func(static item => item.Key); + global::System.Linq.Expressions.Expression> convertToKeyExpression = static item => item.Key; + + var enumType = typeof(global::Thinktecture.Tests.TestEnum); + var metadata = new global::Thinktecture.Internal.KeyedValueObjectMetadata(enumType, typeof(string), true, false, convertFromKey, convertFromKeyExpression, null, convertToKey, convertToKeyExpression); + + global::Thinktecture.Internal.KeyedValueObjectMetadataLookup.AddMetadata(enumType, metadata); + } + + private static readonly global::System.Lazy> _itemsLookup + = new global::System.Lazy>(GetLookup, global::System.Threading.LazyThreadSafetyMode.PublicationOnly); + + private static readonly global::System.Lazy> _items + = new global::System.Lazy>(() => global::System.Linq.Enumerable.ToList(_itemsLookup.Value.Values).AsReadOnly(), global::System.Threading.LazyThreadSafetyMode.PublicationOnly); + + /// + /// Gets all valid items. + /// + public static global::System.Collections.Generic.IReadOnlyList Items => _items.Value; + + /// + /// The identifier of this item. + /// + public string Key { get; } + + private readonly int _hashCode; + + private TestEnum(string key, global::System.Func?>? prop1) + { + ValidateConstructorArguments(ref key, ref prop1); + + if (key is null) + throw new global::System.ArgumentNullException(nameof(key)); + + this.Key = key; + this.Prop1 = prop1; + this._hashCode = global::System.HashCode.Combine(typeof(global::Thinktecture.Tests.TestEnum), global::System.StringComparer.OrdinalIgnoreCase.GetHashCode(key)); + } + + static partial void ValidateConstructorArguments(ref string key, ref global::System.Func?>? prop1); + + /// + /// Gets the identifier of the item. + /// + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + string global::Thinktecture.IValueObjectConvertable.ToValue() + { + return this.Key; + } + + /// + /// Gets an enumeration item for provided . + /// + /// The identifier to return an enumeration item for. + /// An instance of if is not null; otherwise null. + /// If there is no item with the provided . + [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("key")] + public static global::Thinktecture.Tests.TestEnum? Get(string? key) + { + if (key is null) + return default; + + if (!_itemsLookup.Value.TryGetValue(key, out var item)) + { + throw new global::Thinktecture.UnknownEnumIdentifierException(typeof(global::Thinktecture.Tests.TestEnum), key); + } + + return item; + } + + /// + /// Gets a valid enumeration item for provided if a valid item exists. + /// + /// The identifier to return an enumeration item for. + /// An instance of . + /// true if a valid item with provided exists; false otherwise. + public static bool TryGet([global::System.Diagnostics.CodeAnalysis.AllowNull] string key, [global::System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out global::Thinktecture.Tests.TestEnum item) + { + if (key is null) + { + item = default; + return false; + } + + return _itemsLookup.Value.TryGetValue(key, out item); + } + + /// + /// Validates the provided and returns a valid enumeration item if found. + /// + /// The identifier to return an enumeration item for. + /// An object that provides culture-specific formatting information. + /// An instance of . + /// null if a valid item with provided exists; with an error message otherwise. + public static global::Thinktecture.ValidationError? Validate([global::System.Diagnostics.CodeAnalysis.AllowNull] string key, global::System.IFormatProvider? provider, [global::System.Diagnostics.CodeAnalysis.MaybeNull] out global::Thinktecture.Tests.TestEnum item) + { + if(global::Thinktecture.Tests.TestEnum.TryGet(key, out item)) + { + return null; + } + else + { + return global::Thinktecture.Internal.ValidationErrorCreator.CreateValidationError($"There is no item of type 'TestEnum' with the identifier '{key}'."); + } + } + + /// + /// Implicit conversion to the type . + /// + /// Item to covert. + /// The of provided or default if is null. + [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("item")] + public static implicit operator string?(global::Thinktecture.Tests.TestEnum? item) + { + return item is null ? default : item.Key; + } + + /// + /// Explicit conversion from the type . + /// + /// Value to covert. + /// An instance of if the is a known item or implements . + [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("key")] + public static explicit operator global::Thinktecture.Tests.TestEnum?(string? key) + { + return global::Thinktecture.Tests.TestEnum.Get(key); + } + + /// + public bool Equals(global::Thinktecture.Tests.TestEnum? other) + { + return global::System.Object.ReferenceEquals(this, other); + } + + /// + public override bool Equals(object? other) + { + return other is global::Thinktecture.Tests.TestEnum item && Equals(item); + } + + /// + public override int GetHashCode() + { + return _hashCode; + } + + /// + public override string ToString() + { + return this.Key.ToString(); + } + + /// + /// Executes an action depending on the current item. + /// + /// The item to compare to. + /// The action to execute if the current item is equal to . + /// The item to compare to. + /// The action to execute if the current item is equal to . + public void Switch( + TestEnum testEnum1, global::System.Action testEnumAction1, + TestEnum testEnum2, global::System.Action testEnumAction2) + { + if (this == testEnum1) + { + testEnumAction1(); + } + else if (this == testEnum2) + { + testEnumAction2(); + } + else + { + throw new global::System.ArgumentOutOfRangeException($"No action provided for the item '{this}'."); + } + } + + /// + /// Executes an action depending on the current item. + /// + /// Context to be passed to the callbacks. + /// The item to compare to. + /// The action to execute if the current item is equal to . + /// The item to compare to. + /// The action to execute if the current item is equal to . + public void Switch( + TContext context, + TestEnum testEnum1, global::System.Action testEnumAction1, + TestEnum testEnum2, global::System.Action testEnumAction2) + { + if (this == testEnum1) + { + testEnumAction1(context); + } + else if (this == testEnum2) + { + testEnumAction2(context); + } + else + { + throw new global::System.ArgumentOutOfRangeException($"No action provided for the item '{this}'."); + } + } + + /// + /// Executes a function depending on the current item. + /// + /// The item to compare to. + /// The function to execute if the current item is equal to . + /// The item to compare to. + /// The function to execute if the current item is equal to . + public TResult Switch( + TestEnum testEnum1, global::System.Func testEnumFunc1, + TestEnum testEnum2, global::System.Func testEnumFunc2) + { + if (this == testEnum1) + { + return testEnumFunc1(); + } + else if (this == testEnum2) + { + return testEnumFunc2(); + } + else + { + throw new global::System.ArgumentOutOfRangeException($"No function provided for the item '{this}'."); + } + } + + /// + /// Executes a function depending on the current item. + /// + /// Context to be passed to the callbacks. + /// The item to compare to. + /// The function to execute if the current item is equal to . + /// The item to compare to. + /// The function to execute if the current item is equal to . + public TResult Switch( + TContext context, + TestEnum testEnum1, global::System.Func testEnumFunc1, + TestEnum testEnum2, global::System.Func testEnumFunc2) + { + if (this == testEnum1) + { + return testEnumFunc1(context); + } + else if (this == testEnum2) + { + return testEnumFunc2(context); + } + else + { + throw new global::System.ArgumentOutOfRangeException($"No function provided for the item '{this}'."); + } + } + + /// + /// Maps an item to an instance of type . + /// + /// The item to compare to. + /// The instance to return if the current item is equal to . + /// The item to compare to. + /// The instance to return if the current item is equal to . + public TResult Map( + TestEnum testEnum1, TResult other1, + TestEnum testEnum2, TResult other2) + { + if (this == testEnum1) + { + return other1; + } + else if (this == testEnum2) + { + return other2; + } + else + { + throw new global::System.ArgumentOutOfRangeException($"No instance provided for the item '{this}'."); + } + } + + private static global::System.Collections.Generic.IReadOnlyDictionary GetLookup() + { + var lookup = new global::System.Collections.Generic.Dictionary(2, global::System.StringComparer.OrdinalIgnoreCase); + + void AddItem(global::Thinktecture.Tests.TestEnum item, string itemName) + { + if (item is null) + throw new global::System.ArgumentNullException($"The item \"{itemName}\" of type \"TestEnum\" must not be null."); + + if (item.Key is null) + throw new global::System.ArgumentException($"The \"Key\" of the item \"{itemName}\" of type \"TestEnum\" must not be null."); + + if (lookup.ContainsKey(item.Key)) + throw new global::System.ArgumentException($"The type \"TestEnum\" has multiple items with the identifier \"{item.Key}\"."); + + lookup.Add(item.Key, item); + } + + AddItem(@Item1, nameof(@Item1)); + AddItem(@Item2, nameof(@Item2)); + + #if NET8_0_OR_GREATER + return global::System.Collections.Frozen.FrozenDictionary.ToFrozenDictionary(lookup, global::System.StringComparer.OrdinalIgnoreCase); + #else + return lookup; + #endif + } + } + } + + """); + AssertOutput(comparableOutput, _COMPARABLE_OUTPUT_CLASS_STRING_BASED); + AssertOutput(parsableOutput, _PARSABLE_OUTPUT_CLASS_STRING_BASED); + AssertOutput(comparisonOperatorsOutput, _COMPARISON_OPERATORS_OUTPUT_CLASS_STRING_BASED); + AssertOutput(equalityComparisonOperators, _EQUALITY_COMPARABLE_OPERATORS_CLASS); + } } diff --git a/test/Thinktecture.Runtime.Extensions.SourceGenerator.Tests/SourceGeneratorTests/ValueObjectSourceGeneratorTests.cs b/test/Thinktecture.Runtime.Extensions.SourceGenerator.Tests/SourceGeneratorTests/ValueObjectSourceGeneratorTests.cs index 99904050..7d89eb2e 100644 --- a/test/Thinktecture.Runtime.Extensions.SourceGenerator.Tests/SourceGeneratorTests/ValueObjectSourceGeneratorTests.cs +++ b/test/Thinktecture.Runtime.Extensions.SourceGenerator.Tests/SourceGeneratorTests/ValueObjectSourceGeneratorTests.cs @@ -1892,6 +1892,191 @@ public class TestValueObject AssertOutput(output, null); } + [Fact] + public void Should_generate_complex_class_with_nullable_members() + { + var source = """ + + using System; + using Thinktecture; + + namespace Thinktecture.Tests + { + [ComplexValueObject] + public partial class TestValueObject + { + public string? Prop1 { get; } + public Func?>? Prop2 { get; } + + static partial void ValidateFactoryArguments(ref ValidationError? validationError, ref string? prop1, ref Func?>? prop2) + { + } + } + } + + """; + var output = GetGeneratedOutput(source, typeof(ComplexValueObjectAttribute).Assembly); + + AssertOutput(output, _GENERATED_HEADER + """ + + namespace Thinktecture.Tests + { + partial class TestValueObject : global::System.IEquatable, + global::System.Numerics.IEqualityOperators, + global::Thinktecture.IComplexValueObject + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void ModuleInit() + { + global::System.Linq.Expressions.Expression> action = o => new + { + o.Prop1, + o.Prop2 + }; + + var members = new global::System.Collections.Generic.List(); + + foreach (var arg in ((global::System.Linq.Expressions.NewExpression)action.Body).Arguments) + { + members.Add(((global::System.Linq.Expressions.MemberExpression)arg).Member); + } + + var type = typeof(global::Thinktecture.Tests.TestValueObject); + var metadata = new global::Thinktecture.Internal.ComplexValueObjectMetadata(type, members.AsReadOnly()); + + global::Thinktecture.Internal.ComplexValueObjectMetadataLookup.AddMetadata(type, metadata); + } + + private static readonly int _typeHashCode = typeof(global::Thinktecture.Tests.TestValueObject).GetHashCode(); + + public static global::Thinktecture.ValidationError? Validate( + string? prop1, + global::System.Func?>? prop2, + out global::Thinktecture.Tests.TestValueObject? obj) + { + global::Thinktecture.ValidationError? validationError = null; + ValidateFactoryArguments(ref validationError, ref prop1, ref prop2); + + if (validationError is null) + { + obj = new global::Thinktecture.Tests.TestValueObject(prop1, prop2); + obj.FactoryPostInit(); + } + else + { + obj = default; + } + + return validationError; + } + + public static global::Thinktecture.Tests.TestValueObject Create(string? prop1, global::System.Func?>? prop2) + { + var validationError = Validate(prop1, prop2, out global::Thinktecture.Tests.TestValueObject? obj); + + if (validationError is not null) + throw new global::System.ComponentModel.DataAnnotations.ValidationException(validationError.ToString() ?? "Validation failed."); + + return obj!; + } + + public static bool TryCreate( + string? prop1, + global::System.Func?>? prop2, + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out global::Thinktecture.Tests.TestValueObject? obj) + { + return TryCreate(prop1, prop2, out obj, out _); + } + + public static bool TryCreate( + string? prop1, + global::System.Func?>? prop2, + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out global::Thinktecture.Tests.TestValueObject? obj, + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(false)] out global::Thinktecture.ValidationError? validationError) + { + validationError = Validate(prop1, prop2, out obj); + + return validationError is null; + } + + static partial void ValidateFactoryArguments(ref global::Thinktecture.ValidationError? validationError, ref string? prop1, ref global::System.Func?>? prop2); + + partial void FactoryPostInit(); + + private TestValueObject(string? prop1, global::System.Func?>? prop2) + { + ValidateConstructorArguments(ref prop1, ref prop2); + + this.Prop1 = prop1; + this.Prop2 = prop2; + } + + static partial void ValidateConstructorArguments(ref string? prop1, ref global::System.Func?>? prop2); + + /// + /// Compares to instances of . + /// + /// Instance to compare. + /// Another instance to compare. + /// true if objects are equal; otherwise false. + public static bool operator ==(global::Thinktecture.Tests.TestValueObject? obj, global::Thinktecture.Tests.TestValueObject? other) + { + if (obj is null) + return other is null; + + return obj.Equals(other); + } + + /// + /// Compares to instances of . + /// + /// Instance to compare. + /// Another instance to compare. + /// false if objects are equal; otherwise true. + public static bool operator !=(global::Thinktecture.Tests.TestValueObject? obj, global::Thinktecture.Tests.TestValueObject? other) + { + return !(obj == other); + } + + /// + public override bool Equals(object? other) + { + return other is global::Thinktecture.Tests.TestValueObject obj && Equals(obj); + } + + /// + public bool Equals(global::Thinktecture.Tests.TestValueObject? other) + { + if (other is null) + return false; + + if (global::System.Object.ReferenceEquals(this, other)) + return true; + + return global::System.StringComparer.OrdinalIgnoreCase.Equals(this.Prop1, other.Prop1) + && (this.Prop2 is null ? other.Prop2 is null : this.Prop2.Equals(other.Prop2)); + } + + /// + public override int GetHashCode() + { + return global::System.HashCode.Combine( + _typeHashCode, + this.Prop1, + this.Prop2); + } + + /// + public override string ToString() + { + return $"{{ Prop1 = {this.Prop1}, Prop2 = {this.Prop2} }}"; + } + } + } + + """); + } + [Fact] public void Should_generate_complex_class_with_post_init_method_if_validation_method_returns_struct() { diff --git a/test/Thinktecture.Runtime.Extensions.Tests.Shared/TestEnums/TestEnumWithNullableMembers.cs b/test/Thinktecture.Runtime.Extensions.Tests.Shared/TestEnums/TestEnumWithNullableMembers.cs new file mode 100644 index 00000000..53a1e7ee --- /dev/null +++ b/test/Thinktecture.Runtime.Extensions.Tests.Shared/TestEnums/TestEnumWithNullableMembers.cs @@ -0,0 +1,20 @@ +using System; +using System.Threading.Tasks; + +namespace Thinktecture.Runtime.Tests.TestEnums; + +[SmartEnum] +public sealed partial class TestEnumWithNullableMembers +{ + public static readonly TestEnumWithNullableMembers Item1 = new(1, "Item1", TestFuncAsync); + + public string? Prop1 { get; } + + public Func?>? Prop2 { get; } + + // ReSharper disable once InconsistentNaming + private static Task? TestFuncAsync(string? arg) + { + return null; + } +} diff --git a/test/Thinktecture.Runtime.Extensions.Tests.Shared/TestValueObjects/BoundaryWithNullableMembers.cs b/test/Thinktecture.Runtime.Extensions.Tests.Shared/TestValueObjects/BoundaryWithNullableMembers.cs new file mode 100644 index 00000000..ebd654fa --- /dev/null +++ b/test/Thinktecture.Runtime.Extensions.Tests.Shared/TestValueObjects/BoundaryWithNullableMembers.cs @@ -0,0 +1,15 @@ +using System; +using System.Threading.Tasks; + +namespace Thinktecture.Runtime.Tests.TestValueObjects; + +[ComplexValueObject] +public sealed partial class BoundaryWithNullableMembers +{ + public string? Prop1 { get; } + public Func?>? Prop2 { get; } + + static partial void ValidateFactoryArguments(ref ValidationError? validationError, ref string? prop1, ref Func?>? prop2) + { + } +}