Skip to content

Commit

Permalink
Fixed generating factory methods for nested generic types
Browse files Browse the repository at this point in the history
  • Loading branch information
hugener committed May 18, 2024
1 parent 51de54d commit 5ce5c34
Show file tree
Hide file tree
Showing 11 changed files with 86 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

namespace Sundew.DiscriminatedUnions.Generator;

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
Expand All @@ -16,7 +15,6 @@ namespace Sundew.DiscriminatedUnions.Generator;
using Sundew.DiscriminatedUnions.Generator.DeclarationStage;
using Sundew.DiscriminatedUnions.Generator.Model;
using static Sundew.DiscriminatedUnions.Generator.OutputStage.GeneratorConstants;
using Type = Sundew.DiscriminatedUnions.Generator.Model.Type;

internal static class CodeAnalysisHelper
{
Expand Down Expand Up @@ -147,27 +145,27 @@ public static Type GetSourceType(this ITypeSymbol typeSymbol)
switch (typeSymbol)
{
case INamedTypeSymbol namedTypeSymbol:
var (name, nestedTypeQualifier, @namespace, isShortNameAlias) = GetName(namedTypeSymbol);
var (name, _, attributeName, @namespace, isShortNameAlias) = GetNames(namedTypeSymbol);
return new Type(
name,
isShortNameAlias ? string.Empty : @namespace,
nestedTypeQualifier,
attributeName,
isShortNameAlias ? string.Empty : GlobalAssemblyAlias,
namedTypeSymbol.TypeParameters.Length,
false);
case IArrayTypeSymbol arrayTypeSymbol:
var (elementName, elementNestedTypeQualifier, @elementNamespace, elementIsShortNameAlias) = GetName(arrayTypeSymbol.ElementType);
var (elementName, _, elementAttributeName, @elementNamespace, elementIsShortNameAlias) = GetNames(arrayTypeSymbol.ElementType);
return new Type(
elementName,
elementIsShortNameAlias || arrayTypeSymbol.ElementType is ITypeParameterSymbol ? string.Empty : @elementNamespace,
elementNestedTypeQualifier,
elementAttributeName,
elementIsShortNameAlias ? string.Empty : GlobalAssemblyAlias,
0,
true);
case ITypeParameterSymbol typeParameterSymbol:
return new Type(typeParameterSymbol.MetadataName, string.Empty, string.Empty, string.Empty, 0, false);
default:
throw new ArgumentOutOfRangeException(nameof(typeSymbol));
throw new System.ArgumentOutOfRangeException(nameof(typeSymbol));
}
}

Expand All @@ -188,36 +186,37 @@ public static FullType GetFullType(this ITypeSymbol typeSymbol, bool useFullyQua
switch (typeSymbol)
{
case INamedTypeSymbol namedTypeSymbol:
var (name, nestedTypeQualifier, @namespace, isShortNameAlias) = GetName(namedTypeSymbol);
var (name, fullName, attributeName, @namespace, isShortNameAlias) = GetNames(namedTypeSymbol);
return new FullType(
name,
isShortNameAlias ? string.Empty : @namespace,
nestedTypeQualifier,
attributeName,
isShortNameAlias ? string.Empty : GlobalAssemblyAlias,
false,
new TypeMetadata(
!isShortNameAlias && namedTypeSymbol.IsGenericType
!isShortNameAlias && namedTypeSymbol.IsGenericType && namedTypeSymbol.TypeParameters.Length > 0
? GetGenericQualifier(namedTypeSymbol)
: null,
fullName,
namedTypeSymbol.TypeParameters.Select(x => new TypeParameter(
x.Name,
GetUnderlyingTypeConstraint(x)
.Concat(x.ConstraintTypes.Select(x =>
x.ToDisplayString(FullyQualifiedDisplayFormat)))
.Concat(GetNewConstraints(x)).ToImmutableArray())).ToImmutableArray()));
case IArrayTypeSymbol arrayTypeSymbol:
var (elementName, elementNestedTypeQualifier, elementNamespace, elementIsShortNameAlias) = GetName(arrayTypeSymbol.ElementType);
var (elementName, elementFullName, elementAttributeName, elementNamespace, elementIsShortNameAlias) = GetNames(arrayTypeSymbol.ElementType);
return new FullType(
elementName,
elementNestedTypeQualifier,
elementIsShortNameAlias || arrayTypeSymbol.ElementType is ITypeParameterSymbol ? string.Empty : elementNamespace,
elementAttributeName,
elementIsShortNameAlias ? string.Empty : GlobalAssemblyAlias,
true,
new TypeMetadata(null, ImmutableArray<TypeParameter>.Empty));
new TypeMetadata(null, elementFullName, ImmutableArray<TypeParameter>.Empty));
case ITypeParameterSymbol typeParameterSymbol:
return new FullType(typeParameterSymbol.MetadataName, string.Empty, string.Empty, string.Empty, false, new TypeMetadata(null, ImmutableArray<TypeParameter>.Empty));
return new FullType(typeParameterSymbol.MetadataName, string.Empty, string.Empty, string.Empty, false, new TypeMetadata(null, string.Empty, ImmutableArray<TypeParameter>.Empty));
default:
throw new ArgumentOutOfRangeException(nameof(typeSymbol));
throw new System.ArgumentOutOfRangeException(nameof(typeSymbol));
}
}

Expand Down Expand Up @@ -248,8 +247,10 @@ private static IEnumerable<string> GetUnderlyingTypeConstraint(ITypeParameterSym
}
}

private static (string Name, string NestedTypeQualifier, string Namespace, bool IsShortNameAlias) GetName(ITypeSymbol typeSymbol)
private static (string Name, string FullName, string AttributeName, string Namespace, bool IsShortNameAlias) GetNames(ITypeSymbol typeSymbol)
{
var @namespace = typeSymbol.ContainingNamespace.ToDisplayString(NamespaceQualifiedDisplayFormat);
var fullName = typeSymbol.ToDisplayString(FullyQualifiedParameterTypeFormat).Substring(GlobalAssemblyAlias.Length + 3 + @namespace.Length);
switch (typeSymbol.SpecialType)
{
case SpecialType.System_Boolean:
Expand All @@ -266,27 +267,39 @@ private static (string Name, string NestedTypeQualifier, string Namespace, bool
case SpecialType.System_Single:
case SpecialType.System_Double:
case SpecialType.System_String:
return (typeSymbol.ToDisplayString(NameQualifiedTypeFormat), string.Empty, string.Empty, true);
return (fullName, fullName, string.Empty, string.Empty, true);
default:
if (typeSymbol.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
{
return (typeSymbol.ToDisplayString(NameQualifiedTypeFormat), string.Empty, string.Empty, true);
return (fullName, fullName, string.Empty, string.Empty, true);
}

return (typeSymbol.Name, GetNestedName(typeSymbol), typeSymbol.ContainingNamespace.ToDisplayString(NamespaceQualifiedDisplayFormat), false);
return (typeSymbol.Name, fullName, GetAttributeName(typeSymbol), @namespace, false);
}
}

private static string GetNestedName(ITypeSymbol typeSymbol)
private static string GetAttributeName(ITypeSymbol typeSymbol)
{
var stringBuilder = new StringBuilder();
var containingType = typeSymbol.ContainingType;
while (containingType != null)
{
stringBuilder.Append(containingType.Name).Append('.');
stringBuilder.Append(containingType.Name);
if (containingType.IsGenericType && containingType.TypeParameters.Length > 0)
{
stringBuilder.Append('<').Append(',', containingType.TypeParameters.Length - 1).Append('>');
}

stringBuilder.Append('.');
containingType = containingType.ContainingType;
}

stringBuilder.Append(typeSymbol.Name);
if (typeSymbol is INamedTypeSymbol { IsGenericType: true, TypeParameters.Length: > 0 } namedTypeSymbol)
{
stringBuilder.Append('<').Append(',', namedTypeSymbol.TypeParameters.Length - 1).Append('>');
}

return stringBuilder.ToString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,17 @@ namespace Sundew.DiscriminatedUnions.Generator.Model;

using System;

internal readonly record struct FullType(string Name, string Namespace, string NestedTypeQualifier, string AssemblyAlias, bool IsArray, TypeMetadata TypeMetadata) : IEquatable<Type>
internal readonly record struct FullType(string Name, string Namespace, string NameForTypeOfAttribute, string AssemblyAlias, bool IsArray, TypeMetadata TypeMetadata) : IEquatable<Type>
{
public FullType(Type type, TypeMetadata typeMetadata)
: this(type.Name, type.Namespace, type.NestedTypeQualifier, type.AssemblyAlias, type.IsArray, typeMetadata)
: this(type.Name, type.Namespace, type.AttributeName, type.AssemblyAlias, type.IsArray, typeMetadata)
{
}

public bool Equals(Type other)
{
return this.Name.Equals(other.Name) &&
return this.NameForTypeOfAttribute.Equals(other.AttributeName) &&
this.Namespace.Equals(other.Namespace) &&
this.NestedTypeQualifier.Equals(other.NestedTypeQualifier) &&
this.AssemblyAlias.Equals(other.AssemblyAlias) &&
this.IsArray.Equals(other.IsArray) &&
this.TypeMetadata.TypeParameters.Count == other.TypeParameterCount;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@

namespace Sundew.DiscriminatedUnions.Generator.Model;

internal readonly record struct Type(string Name, string Namespace, string NestedTypeQualifier, string AssemblyAlias, int TypeParameterCount, bool IsArray);
internal readonly record struct Type(string Name, string Namespace, string AttributeName, string AssemblyAlias, int TypeParameterCount, bool IsArray);
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ namespace Sundew.DiscriminatedUnions.Generator.Model;
using Sundew.Base.Collections.Immutable;
using Sundew.DiscriminatedUnions.Generator.DeclarationStage;

internal readonly record struct TypeMetadata(string? GenericQualifier, ValueArray<TypeParameter> TypeParameters);
internal readonly record struct TypeMetadata(string? GenericQualifier, string FullName, ValueArray<TypeParameter> TypeParameters);
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,8 @@ public static StringBuilder AppendType(this StringBuilder stringBuilder, in Full
.Append('.');
}

stringBuilder.Append(fullType.NestedTypeQualifier);
stringBuilder.Append(fullType.Name);
stringBuilder.TryAppendGenericQualifier(fullType, omitTypeParameters);
stringBuilder.Append(omitTypeParameters ? fullType.NameForTypeOfAttribute : fullType.TypeMetadata.FullName);

if (fullType.IsArray)
{
stringBuilder.Append('[').Append(']');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ public partial record NestedGenericUnion<TItem>
/// </summary>
/// <param name="item">The item.</param>
/// <returns>A new Target.</returns>
[Sundew.DiscriminatedUnions.CaseType(typeof(global::Sundew.DiscriminatedUnions.Tester.NestedGenericUnion.Target<>))]
[Sundew.DiscriminatedUnions.CaseType(typeof(global::Sundew.DiscriminatedUnions.Tester.NestedGenericUnion<>.Target))]
public static global::Sundew.DiscriminatedUnions.Tester.NestedGenericUnion<TItem> _Target(TItem item)
=> new global::Sundew.DiscriminatedUnions.Tester.NestedGenericUnion.Target<TItem>.Target(item);
=> new global::Sundew.DiscriminatedUnions.Tester.NestedGenericUnion<TItem>.Target(item);

/// <summary>
/// Factory method for the TargetList case.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>A new TargetList.</returns>
[Sundew.DiscriminatedUnions.CaseType(typeof(global::Sundew.DiscriminatedUnions.Tester.NestedGenericUnion.TargetList<>))]
[Sundew.DiscriminatedUnions.CaseType(typeof(global::Sundew.DiscriminatedUnions.Tester.NestedGenericUnion<>.TargetList))]
public static global::Sundew.DiscriminatedUnions.Tester.NestedGenericUnion<TItem> _TargetList(global::System.Collections.Generic.List<TItem> item)
=> new global::Sundew.DiscriminatedUnions.Tester.NestedGenericUnion.TargetList<TItem>.TargetList(item);
=> new global::Sundew.DiscriminatedUnions.Tester.NestedGenericUnion<TItem>.TargetList(item);
}
}
Loading

0 comments on commit 5ce5c34

Please sign in to comment.