using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using XamlX.TypeSystem; namespace Robust.Client.NameGenerator { /// /// Taken from https://github.com/AvaloniaUI/Avalonia.NameGenerator/blob/ecc9677a23de5cbc90af07ccac14e31c0da41d6a/src/Avalonia.NameGenerator/Infrastructure/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 IReadOnlyList 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) => null; public IXamlType BaseType => _symbol.BaseType == null ? null : new RoslynType(_symbol.BaseType, _assembly); public bool IsValueType { get; } = false; public bool IsEnum { get; } = false; public IReadOnlyList Interfaces => _symbol.AllInterfaces .Select(abstraction => new RoslynType(abstraction, _assembly)) .ToList(); public bool IsInterface => _symbol.IsAbstract; public IXamlType GetEnumUnderlyingType() => null; 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 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) : null; 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 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 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, _assembly); public IXamlMethod MakeGenericMethod(IReadOnlyList typeArguments) => null; public IReadOnlyList CustomAttributes { get; } = new List(); } }