using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using XamlX.TypeSystem;
namespace Robust.Client.NameGenerator
{
///
/// Taken from https://github.com/AvaloniaUI/Avalonia/blob/9d28762f1439e58e9764d104223b73eef93b26b5/src/tools/Avalonia.Generators/Compiler/RoslynTypeSystem.cs
///
public class RoslynTypeSystem : IXamlTypeSystem
{
private readonly List _assemblies = new List();
public RoslynTypeSystem(CSharpCompilation compilation)
{
_assemblies.Add(new RoslynAssembly(compilation.Assembly));
var assemblySymbols = compilation
.References
.Select(compilation.GetAssemblyOrModuleSymbol)
.OfType()
.Select(assembly => new RoslynAssembly(assembly))
.ToList();
_assemblies.AddRange(assemblySymbols);
}
public IEnumerable Assemblies => _assemblies;
public IXamlAssembly FindAssembly(string substring) => _assemblies[0];
public IXamlType? FindType(string name)
{
foreach (var assembly in _assemblies)
{
var type = assembly.FindType(name);
if (type != null)
return type;
}
return null;
}
public IXamlType? FindType(string name, string assembly)
{
foreach (var assemblyInstance in _assemblies)
{
var type = assemblyInstance.FindType(name);
if (type != null)
return type;
}
return null;
}
}
public class RoslynAssembly : IXamlAssembly
{
private readonly IAssemblySymbol _symbol;
public RoslynAssembly(IAssemblySymbol symbol) => _symbol = symbol;
public bool Equals(IXamlAssembly other) =>
other is RoslynAssembly roslynAssembly &&
SymbolEqualityComparer.Default.Equals(_symbol, roslynAssembly._symbol);
public string Name => _symbol.Name;
public IReadOnlyList CustomAttributes =>
_symbol.GetAttributes()
.Select(data => new RoslynAttribute(data, this))
.ToList();
public IXamlType? FindType(string fullName)
{
var type = _symbol.GetTypeByMetadataName(fullName);
return type is null ? null : new RoslynType(type, this);
}
}
public class RoslynAttribute : IXamlCustomAttribute
{
private readonly AttributeData _data;
private readonly RoslynAssembly _assembly;
public RoslynAttribute(AttributeData data, RoslynAssembly assembly)
{
_data = data;
_assembly = assembly;
}
public bool Equals(IXamlCustomAttribute other) =>
other is RoslynAttribute attribute &&
_data == attribute._data;
public IXamlType Type => new RoslynType(_data.AttributeClass!, _assembly);
public List Parameters =>
_data.ConstructorArguments
.Select(argument => argument.Value)
.ToList();
public Dictionary Properties =>
_data.NamedArguments.ToDictionary(
pair => pair.Key,
pair => pair.Value.Value);
}
public class RoslynType : IXamlType
{
private static readonly SymbolDisplayFormat SymbolDisplayFormat = new SymbolDisplayFormat(
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters |
SymbolDisplayGenericsOptions.IncludeTypeConstraints |
SymbolDisplayGenericsOptions.IncludeVariance);
private readonly RoslynAssembly _assembly;
private readonly INamedTypeSymbol _symbol;
public RoslynType(INamedTypeSymbol symbol, RoslynAssembly assembly)
{
_symbol = symbol;
_assembly = assembly;
}
public bool Equals(IXamlType other) =>
other is RoslynType roslynType &&
SymbolEqualityComparer.Default.Equals(_symbol, roslynType._symbol);
public object Id => _symbol;
public string Name => _symbol.Name;
public string Namespace => _symbol.ContainingNamespace.ToDisplayString(SymbolDisplayFormat);
public string FullName => $"{Namespace}.{Name}";
public IXamlAssembly Assembly => _assembly;
public IReadOnlyList Properties =>
_symbol.GetMembers()
.Where(member => member.Kind == SymbolKind.Property)
.OfType()
.Select(property => new RoslynProperty(property, _assembly))
.ToList();
public IReadOnlyList Events { get; } = new List();
public IReadOnlyList Fields { get; } = new List();
public IReadOnlyList Methods { get; } = new List();
public IReadOnlyList Constructors =>
_symbol.Constructors
.Select(method => new RoslynConstructor(method, _assembly))
.ToList();
public IReadOnlyList CustomAttributes { get; } = new List();
public IReadOnlyList GenericArguments { get; } = new List();
public bool IsAssignableFrom(IXamlType type) => type == this;
public IXamlType MakeGenericType(IReadOnlyList typeArguments) => this;
public IXamlType GenericTypeDefinition => this;
public bool IsArray => false;
public IXamlType? ArrayElementType { get; } = null;
public IXamlType MakeArrayType(int dimensions) => throw new NotImplementedException();
public IXamlType? BaseType => _symbol.BaseType == null ? null : new RoslynType(_symbol.BaseType, _assembly);
public bool IsValueType { get; } = false;
public bool IsEnum { get; } = false;
public bool IsPublic => _symbol.DeclaredAccessibility == Accessibility.Public;
public bool IsNestedPrivate => _symbol.DeclaredAccessibility == Accessibility.Private;
public bool IsFunctionPointer => false;
public IXamlType? DeclaringType =>
_symbol.ContainingType is { } containingType ? new RoslynType(containingType, _assembly) : null;
public IReadOnlyList Interfaces =>
_symbol.AllInterfaces
.Select(abstraction => new RoslynType(abstraction, _assembly))
.ToList();
public bool IsInterface => _symbol.IsAbstract;
public IXamlType GetEnumUnderlyingType() => throw new NotImplementedException();
public IReadOnlyList GenericParameters { get; } = new List();
}
public class RoslynConstructor : IXamlConstructor
{
private readonly IMethodSymbol _symbol;
private readonly RoslynAssembly _assembly;
public RoslynConstructor(IMethodSymbol symbol, RoslynAssembly assembly)
{
_symbol = symbol;
_assembly = assembly;
}
public bool Equals(IXamlConstructor other) =>
other is RoslynConstructor roslynConstructor &&
SymbolEqualityComparer.Default.Equals(_symbol, roslynConstructor._symbol);
public bool IsPublic => true;
public bool IsStatic => false;
public IReadOnlyList Parameters =>
_symbol.Parameters
.Select(parameter => parameter.Type)
.OfType()
.Select(type => new RoslynType(type, _assembly))
.ToList();
public string Name => _symbol.Name;
public IXamlType DeclaringType => new RoslynType(_symbol.ContainingType, _assembly);
public IXamlParameterInfo GetParameterInfo(int index) => new RoslynParameter(_assembly, _symbol.Parameters[index]);
}
public class RoslynProperty : IXamlProperty
{
private readonly IPropertySymbol _symbol;
private readonly RoslynAssembly _assembly;
public RoslynProperty(IPropertySymbol symbol, RoslynAssembly assembly)
{
_symbol = symbol;
_assembly = assembly;
}
public bool Equals(IXamlProperty other) =>
other is RoslynProperty roslynProperty &&
SymbolEqualityComparer.Default.Equals(_symbol, roslynProperty._symbol);
public string Name => _symbol.Name;
public IXamlType PropertyType =>
_symbol.Type is INamedTypeSymbol namedTypeSymbol
? new RoslynType(namedTypeSymbol, _assembly)
: throw new InvalidOperationException($"Roslyn property type {_symbol.Type} is not supported.");
public IXamlType DeclaringType => new RoslynType(_symbol.ContainingType, _assembly);
public IXamlMethod? Getter => _symbol.GetMethod == null ? null : new RoslynMethod(_symbol.GetMethod, _assembly);
public IXamlMethod? Setter => _symbol.SetMethod == null ? null : new RoslynMethod(_symbol.SetMethod, _assembly);
public IReadOnlyList CustomAttributes { get; } = new List();
public IReadOnlyList IndexerParameters { get; } = new List();
}
public class RoslynParameter : IXamlParameterInfo
{
private readonly RoslynAssembly _assembly;
private readonly IParameterSymbol _symbol;
public RoslynParameter(RoslynAssembly assembly, IParameterSymbol symbol)
{
_assembly = assembly;
_symbol = symbol;
}
public string Name => _symbol.Name;
public IXamlType ParameterType => new RoslynType((INamedTypeSymbol)_symbol.Type, _assembly);
public IReadOnlyList CustomAttributes => Array.Empty();
}
public class RoslynMethod : IXamlMethod
{
private readonly IMethodSymbol _symbol;
private readonly RoslynAssembly _assembly;
public RoslynMethod(IMethodSymbol symbol, RoslynAssembly assembly)
{
_symbol = symbol;
_assembly = assembly;
}
public bool Equals(IXamlMethod other) =>
other is RoslynMethod roslynMethod &&
SymbolEqualityComparer.Default.Equals(roslynMethod._symbol, _symbol);
public string Name => _symbol.Name;
public bool IsPublic => true;
public bool IsPrivate => _symbol.DeclaredAccessibility == Accessibility.Private;
public bool IsFamily => _symbol.DeclaredAccessibility == Accessibility.Protected;
public bool ContainsGenericParameters => _symbol.TypeParameters.Any();
public bool IsGenericMethod => _symbol.IsGenericMethod;
public bool IsGenericMethodDefinition => _symbol.IsDefinition && _symbol.IsGenericMethod;
public bool IsStatic => false;
public IXamlType ReturnType => new RoslynType((INamedTypeSymbol) _symbol.ReturnType, _assembly);
public IReadOnlyList Parameters =>
_symbol.Parameters.Select(parameter => parameter.Type)
.OfType()
.Select(type => new RoslynType(type, _assembly))
.ToList();
public IXamlType DeclaringType => new RoslynType((INamedTypeSymbol)_symbol.ReceiverType! as INamedTypeSymbol, _assembly);
public IReadOnlyList GenericParameters => throw new NotImplementedException();
public IReadOnlyList GenericArguments => _symbol.TypeArguments
.Select(ga => new RoslynType((INamedTypeSymbol)ga, _assembly))
.ToArray();
public IXamlMethod MakeGenericMethod(IReadOnlyList typeArguments) => throw new NotImplementedException();
public IReadOnlyList CustomAttributes { get; } = new List();
public IXamlParameterInfo GetParameterInfo(int index) => new RoslynParameter(_assembly, _symbol.Parameters[index]);
}
}