committed by
GitHub
12 changed files with 442 additions and 134 deletions
@ -0,0 +1,42 @@ |
|||
using System; |
|||
using XamlX.Compiler; |
|||
using XamlX.Emit; |
|||
using XamlX.Transform; |
|||
using XamlX.Transform.Transformers; |
|||
using XamlX.TypeSystem; |
|||
|
|||
namespace XamlNameReferenceGenerator.Infrastructure |
|||
{ |
|||
internal sealed class MiniCompiler : XamlCompiler<object, IXamlEmitResult> |
|||
{ |
|||
public static MiniCompiler CreateDefault(RoslynTypeSystem typeSystem) |
|||
{ |
|||
var avaloniaXmlns = typeSystem.GetType("Avalonia.Metadata.XmlnsDefinitionAttribute"); |
|||
var configuration = new TransformerConfiguration( |
|||
typeSystem, |
|||
typeSystem.Assemblies[0], |
|||
new XamlLanguageTypeMappings(typeSystem) {XmlnsAttributes = {avaloniaXmlns}}); |
|||
return new MiniCompiler(configuration); |
|||
} |
|||
|
|||
private MiniCompiler(TransformerConfiguration configuration) |
|||
: base(configuration, new XamlLanguageEmitMappings<object, IXamlEmitResult>(), false) |
|||
{ |
|||
Transformers.Add(new KnownDirectivesTransformer()); |
|||
Transformers.Add(new XamlIntrinsicsTransformer()); |
|||
Transformers.Add(new XArgumentsTransformer()); |
|||
Transformers.Add(new TypeReferenceResolver()); |
|||
Transformers.Add(new MarkupExtensionTransformer()); |
|||
Transformers.Add(new PropertyReferenceResolver()); |
|||
Transformers.Add(new ResolvePropertyValueAddersTransformer()); |
|||
Transformers.Add(new ConstructableObjectTransformer()); |
|||
} |
|||
|
|||
protected override XamlEmitContext<object, IXamlEmitResult> InitCodeGen( |
|||
IFileSource file, |
|||
Func<string, IXamlType, IXamlTypeBuilder<object>> createSubType, |
|||
object codeGen, XamlRuntimeContext<object, IXamlEmitResult> context, |
|||
bool needContextLocal) => |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
using System.Collections.Generic; |
|||
using XamlX.Ast; |
|||
|
|||
namespace XamlNameReferenceGenerator.Infrastructure |
|||
{ |
|||
internal sealed class MiniNamedControlCollector : IXamlAstVisitor |
|||
{ |
|||
private readonly List<(string TypeName, string Name)> _items = new List<(string TypeName, string Name)>(); |
|||
|
|||
public IReadOnlyList<(string TypeName, string Name)> Controls => _items; |
|||
|
|||
public IXamlAstNode Visit(IXamlAstNode node) |
|||
{ |
|||
if (!(node is XamlAstConstructableObjectNode constructableObjectNode)) |
|||
return node; |
|||
|
|||
foreach (var child in constructableObjectNode.Children) |
|||
{ |
|||
var nameValue = ResolveNameDirectiveOrDefault(child); |
|||
if (nameValue == null) continue; |
|||
|
|||
var clrType = constructableObjectNode.Type.GetClrType(); |
|||
var typeNamePair = ($@"{clrType.Namespace}.{clrType.Name}", nameValue); |
|||
if (!_items.Contains(typeNamePair)) |
|||
{ |
|||
_items.Add(typeNamePair); |
|||
} |
|||
} |
|||
|
|||
return node; |
|||
} |
|||
|
|||
public void Push(IXamlAstNode node) { } |
|||
|
|||
public void Pop() { } |
|||
|
|||
private static string ResolveNameDirectiveOrDefault(IXamlAstNode node) => |
|||
node switch |
|||
{ |
|||
XamlAstXamlPropertyValueNode propertyValueNode when |
|||
propertyValueNode.Property is XamlAstClrProperty reference && |
|||
reference.Name == "Name" && |
|||
propertyValueNode.Values.Count > 0 && |
|||
propertyValueNode.Values[0] is XamlAstTextNode nameNode => nameNode.Text, |
|||
|
|||
XamlAstXmlDirective xmlDirective when |
|||
xmlDirective.Name == "Name" && |
|||
xmlDirective.Values.Count > 0 && |
|||
xmlDirective.Values[0] is XamlAstTextNode xNameNode => xNameNode.Text, |
|||
|
|||
_ => null |
|||
}; |
|||
} |
|||
} |
|||
@ -1,13 +1,14 @@ |
|||
using System; |
|||
using System.IO; |
|||
|
|||
namespace XamlNameReferenceGenerator |
|||
namespace XamlNameReferenceGenerator.Infrastructure |
|||
{ |
|||
internal class NameReferenceDebugger |
|||
internal class PhysicalFileDebugger |
|||
{ |
|||
private const string DefaultPath = @"C:\Users\prizr\Documents\GitHub\XamlNameReferenceGenerator\debug.txt"; |
|||
private readonly string _path; |
|||
|
|||
public NameReferenceDebugger(string path) => _path = path; |
|||
public PhysicalFileDebugger(string path = DefaultPath) => _path = path; |
|||
|
|||
public string Debug(Func<string> function) |
|||
{ |
|||
@ -0,0 +1,281 @@ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Microsoft.CodeAnalysis; |
|||
using Microsoft.CodeAnalysis.CSharp; |
|||
using XamlX.TypeSystem; |
|||
|
|||
namespace XamlNameReferenceGenerator.Infrastructure |
|||
{ |
|||
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 IReadOnlyList<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) => 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<IXamlType> Interfaces { get; } = new List<IXamlType>(); |
|||
|
|||
public bool IsInterface { get; } = false; |
|||
|
|||
public IXamlType GetEnumUnderlyingType() => null; |
|||
|
|||
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 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<IXamlCustomAttribute> CustomAttributes { get; } = new List<IXamlCustomAttribute>(); |
|||
|
|||
public IReadOnlyList<IXamlType> IndexerParameters { get; } = new List<IXamlType>(); |
|||
} |
|||
|
|||
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<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, _assembly); |
|||
|
|||
public IXamlMethod MakeGenericMethod(IReadOnlyList<IXamlType> typeArguments) => null; |
|||
|
|||
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes { get; } = new List<IXamlCustomAttribute>(); |
|||
} |
|||
} |
|||
@ -1,12 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace XamlNameReferenceGenerator.Parsers |
|||
{ |
|||
public class XamlXCompiledNameReferenceXamlParser : INameReferenceXamlParser |
|||
{ |
|||
public List<(string TypeName, string Name)> GetNamedControls(string xaml) |
|||
{ |
|||
throw new System.NotImplementedException(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
using System.Collections.Generic; |
|||
using Microsoft.CodeAnalysis.CSharp; |
|||
using XamlNameReferenceGenerator.Infrastructure; |
|||
using XamlX; |
|||
using XamlX.Parsers; |
|||
|
|||
namespace XamlNameReferenceGenerator.Parsers |
|||
{ |
|||
internal class XamlXNameReferenceXamlParser : INameReferenceXamlParser |
|||
{ |
|||
private readonly CSharpCompilation _compilation; |
|||
|
|||
public XamlXNameReferenceXamlParser(CSharpCompilation compilation) => _compilation = compilation; |
|||
|
|||
public IReadOnlyList<(string TypeName, string Name)> GetNamedControls(string xaml) |
|||
{ |
|||
var parsed = XDocumentXamlParser.Parse(xaml, new Dictionary<string, string> |
|||
{ |
|||
{XamlNamespaces.Blend2008, XamlNamespaces.Blend2008} |
|||
}); |
|||
|
|||
MiniCompiler |
|||
.CreateDefault(new RoslynTypeSystem(_compilation)) |
|||
.Transform(parsed); |
|||
|
|||
var visitor = new MiniNamedControlCollector(); |
|||
parsed.Root.Visit(visitor); |
|||
parsed.Root.VisitChildren(visitor); |
|||
return visitor.Controls; |
|||
} |
|||
} |
|||
} |
|||
@ -1,67 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
using XamlX; |
|||
using XamlX.Ast; |
|||
using XamlX.Parsers; |
|||
|
|||
namespace XamlNameReferenceGenerator.Parsers |
|||
{ |
|||
public class XamlXRawNameReferenceXamlParser : INameReferenceXamlParser |
|||
{ |
|||
public List<(string TypeName, string Name)> GetNamedControls(string xaml) |
|||
{ |
|||
var parsed = XDocumentXamlParser.Parse(xaml, new Dictionary<string, string> |
|||
{ |
|||
{XamlNamespaces.Blend2008, XamlNamespaces.Blend2008} |
|||
}); |
|||
|
|||
var visitor = new XamlAstCollector(); |
|||
parsed.Root.Visit(visitor); |
|||
parsed.Root.VisitChildren(visitor); |
|||
return visitor.Controls; |
|||
} |
|||
|
|||
private class XamlAstCollector : IXamlAstVisitor |
|||
{ |
|||
public List<(string TypeName, string Name)> Controls { get; } = new List<(string TypeName, string Name)>(); |
|||
|
|||
public IXamlAstNode Visit(IXamlAstNode node) |
|||
{ |
|||
if (node is XamlAstObjectNode element && element.Type is XamlAstXmlTypeReference type) |
|||
{ |
|||
foreach (var child in element.Children) |
|||
{ |
|||
var nameValue = ResolveNameDirectiveOrDefault(child); |
|||
if (nameValue == null) continue; |
|||
|
|||
var typeNamePair = (type.Name, nameValue); |
|||
if (!Controls.Contains(typeNamePair)) |
|||
Controls.Add(typeNamePair); |
|||
} |
|||
} |
|||
|
|||
return node; |
|||
} |
|||
|
|||
public void Push(IXamlAstNode node) { } |
|||
|
|||
public void Pop() { } |
|||
|
|||
private static string ResolveNameDirectiveOrDefault(IXamlAstNode node) => |
|||
node switch |
|||
{ |
|||
XamlAstXamlPropertyValueNode propertyValueNode when |
|||
propertyValueNode.Property is XamlAstNamePropertyReference reference && |
|||
reference.Name == "Name" && |
|||
propertyValueNode.Values.Count > 0 && |
|||
propertyValueNode.Values[0] is XamlAstTextNode nameNode => nameNode.Text, |
|||
|
|||
XamlAstXmlDirective xmlDirective when |
|||
xmlDirective.Name == "Name" && |
|||
xmlDirective.Values.Count > 0 && |
|||
xmlDirective.Values[0] is XamlAstTextNode xNameNode => xNameNode.Text, |
|||
|
|||
_ => null |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue