mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-15 23:02:34 +02:00
339 lines
12 KiB
C#
339 lines
12 KiB
C#
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
using XamlX.TypeSystem;
|
|
|
|
namespace Robust.Client.NameGenerator
|
|
{
|
|
/// <summary>
|
|
/// Taken from https://github.com/AvaloniaUI/Avalonia/blob/9d28762f1439e58e9764d104223b73eef93b26b5/src/tools/Avalonia.Generators/Compiler/RoslynTypeSystem.cs
|
|
/// </summary>
|
|
public class RoslynTypeSystem : IXamlTypeSystem
|
|
{
|
|
private readonly List<IXamlAssembly> _assemblies = new List<IXamlAssembly>();
|
|
|
|
public RoslynTypeSystem(CSharpCompilation compilation)
|
|
{
|
|
_assemblies.Add(new RoslynAssembly(compilation.Assembly));
|
|
|
|
var assemblySymbols = compilation
|
|
.References
|
|
.Select(compilation.GetAssemblyOrModuleSymbol)
|
|
.OfType<IAssemblySymbol>()
|
|
.Select(assembly => new RoslynAssembly(assembly))
|
|
.ToList();
|
|
|
|
_assemblies.AddRange(assemblySymbols);
|
|
}
|
|
|
|
public IEnumerable<IXamlAssembly> 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<IXamlCustomAttribute> 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<object?> Parameters =>
|
|
_data.ConstructorArguments
|
|
.Select(argument => argument.Value)
|
|
.ToList();
|
|
|
|
public Dictionary<string, object?> 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<IXamlProperty> Properties =>
|
|
_symbol.GetMembers()
|
|
.Where(member => member.Kind == SymbolKind.Property)
|
|
.OfType<IPropertySymbol>()
|
|
.Select(property => new RoslynProperty(property, _assembly))
|
|
.ToList();
|
|
|
|
public IReadOnlyList<IXamlEventInfo> Events { get; } = new List<IXamlEventInfo>();
|
|
|
|
public IReadOnlyList<IXamlField> Fields { get; } = new List<IXamlField>();
|
|
|
|
public IReadOnlyList<IXamlMethod> Methods { get; } = new List<IXamlMethod>();
|
|
|
|
public IReadOnlyList<IXamlConstructor> Constructors =>
|
|
_symbol.Constructors
|
|
.Select(method => new RoslynConstructor(method, _assembly))
|
|
.ToList();
|
|
|
|
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes { get; } = new List<IXamlCustomAttribute>();
|
|
|
|
public IReadOnlyList<IXamlType> GenericArguments { get; } = new List<IXamlType>();
|
|
|
|
public bool IsAssignableFrom(IXamlType type) => type == this;
|
|
|
|
public IXamlType MakeGenericType(IReadOnlyList<IXamlType> 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<IXamlType> Interfaces =>
|
|
_symbol.AllInterfaces
|
|
.Select(abstraction => new RoslynType(abstraction, _assembly))
|
|
.ToList();
|
|
|
|
public bool IsInterface => _symbol.IsAbstract;
|
|
|
|
public IXamlType GetEnumUnderlyingType() => throw new NotImplementedException();
|
|
|
|
public IReadOnlyList<IXamlType> GenericParameters { get; } = new List<IXamlType>();
|
|
}
|
|
|
|
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<IXamlType> Parameters =>
|
|
_symbol.Parameters
|
|
.Select(parameter => parameter.Type)
|
|
.OfType<INamedTypeSymbol>()
|
|
.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<IXamlCustomAttribute> CustomAttributes { get; } = new List<IXamlCustomAttribute>();
|
|
|
|
public IReadOnlyList<IXamlType> IndexerParameters { get; } = new List<IXamlType>();
|
|
}
|
|
|
|
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<IXamlCustomAttribute> CustomAttributes => Array.Empty<IXamlCustomAttribute>();
|
|
}
|
|
|
|
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<IXamlType> Parameters =>
|
|
_symbol.Parameters.Select(parameter => parameter.Type)
|
|
.OfType<INamedTypeSymbol>()
|
|
.Select(type => new RoslynType(type, _assembly))
|
|
.ToList();
|
|
|
|
public IXamlType DeclaringType => new RoslynType((INamedTypeSymbol)_symbol.ReceiverType! as INamedTypeSymbol, _assembly);
|
|
|
|
public IReadOnlyList<IXamlType> GenericParameters => throw new NotImplementedException();
|
|
|
|
public IReadOnlyList<IXamlType> GenericArguments => _symbol.TypeArguments
|
|
.Select(ga => new RoslynType((INamedTypeSymbol)ga, _assembly))
|
|
.ToArray();
|
|
|
|
public IXamlMethod MakeGenericMethod(IReadOnlyList<IXamlType> typeArguments) => throw new NotImplementedException();
|
|
|
|
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes { get; } = new List<IXamlCustomAttribute>();
|
|
|
|
public IXamlParameterInfo GetParameterInfo(int index) => new RoslynParameter(_assembly, _symbol.Parameters[index]);
|
|
}
|
|
}
|