// This file is ported and adapted from CommunityToolkit.Mvvm (CommunityToolkit/dotnet)
namespace MapperSourceGen.SourceGenerator.Model;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using static Microsoft.CodeAnalysis.SymbolDisplayTypeQualificationStyle;
///
/// Represents information about a type hierarchy in a source code file.
///
internal sealed partial class HierarchyInfo : IEquatable
{
///
/// Initializes a new instance of the class.
///
/// The filename hint for the type (including namespace) without extension.
/// The containing namespace for the type.
/// The current hierarchy for the type.
/// is null or empty.
private HierarchyInfo(string fileNameHint, string @namespace, ImmutableArray hierarchy)
{
if ( string.IsNullOrWhiteSpace(fileNameHint) )
{
throw new ArgumentException($"'{nameof(fileNameHint)}' cannot be null or empty.", nameof(fileNameHint));
}
FileNameHint = fileNameHint;
Hierarchy = hierarchy;
Namespace = @namespace;
}
///
/// Gets the file name hint (including full namespace) for the type hierarchy.
///
public string FileNameHint { get; }
///
/// Gets a collection of representing the hierarchy of types.
///
public ImmutableArray Hierarchy { get; }
///
/// Gets the namespace of the type hierarchy.
///
public string Namespace { get; }
public static HierarchyInfo From(INamedTypeSymbol typeSymbol)
{
if ( typeSymbol is null )
{
throw new ArgumentNullException(nameof(typeSymbol));
}
LinkedList hierarchy = [];
for ( INamedTypeSymbol? parent = typeSymbol;
parent is not null;
parent = parent.ContainingType )
{
hierarchy.AddLast(new TypeInfo(parent.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
parent.TypeKind,
parent.DeclaredAccessibility,
parent.IsRecord,
parent.IsSealed));
}
return new HierarchyInfo(typeSymbol.ToDisplayString(new SymbolDisplayFormat(typeQualificationStyle: NameAndContainingTypesAndNamespaces)),
typeSymbol.ContainingNamespace.ToDisplayString(new SymbolDisplayFormat(typeQualificationStyle: NameAndContainingTypesAndNamespaces)),
[..hierarchy]);
}
public static bool operator ==(HierarchyInfo? left, HierarchyInfo? right)
{
return Equals(left, right);
}
public static bool operator !=(HierarchyInfo? left, HierarchyInfo? right)
{
return !Equals(left, right);
}
///
public bool Equals(HierarchyInfo? other)
{
if ( other is null )
{
return false;
}
if ( ReferenceEquals(this, other) )
{
return true;
}
return string.Equals(FileNameHint, other.FileNameHint, StringComparison.OrdinalIgnoreCase)
&& string.Equals(Namespace, other.Namespace, StringComparison.OrdinalIgnoreCase);
}
///
public override bool Equals(object? obj)
{
return ReferenceEquals(this, obj) || ( obj is HierarchyInfo other && Equals(other) );
}
///
public override int GetHashCode()
{
unchecked
{
return ( StringComparer.OrdinalIgnoreCase.GetHashCode(FileNameHint) * 397 )
^ StringComparer.OrdinalIgnoreCase.GetHashCode(Namespace);
}
}
}