Browse Source
* Remove PropertyPath. It was added as part of #2734 with the intention of it being used for animation setters, but this was never implemented. There's no point carrying this old unused code around - if we want to implement this feature we can add it back in. * Update API suppressions.pull/19147/head
committed by
GitHub
7 changed files with 56 additions and 361 deletions
@ -1,91 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
|
|||
namespace Avalonia.Data.Core |
|||
{ |
|||
public class PropertyPath |
|||
{ |
|||
public IReadOnlyList<IPropertyPathElement> Elements { get; } |
|||
|
|||
public PropertyPath(IEnumerable<IPropertyPathElement> elements) |
|||
{ |
|||
Elements = elements.ToArray(); |
|||
} |
|||
} |
|||
|
|||
public class PropertyPathBuilder |
|||
{ |
|||
readonly List<IPropertyPathElement> _elements = new List<IPropertyPathElement>(); |
|||
|
|||
public PropertyPathBuilder Property(IPropertyInfo property) |
|||
{ |
|||
_elements.Add(new PropertyPropertyPathElement(property)); |
|||
return this; |
|||
} |
|||
|
|||
|
|||
public PropertyPathBuilder ChildTraversal() |
|||
{ |
|||
_elements.Add(new ChildTraversalPropertyPathElement()); |
|||
return this; |
|||
} |
|||
|
|||
public PropertyPathBuilder EnsureType(Type type) |
|||
{ |
|||
_elements.Add(new EnsureTypePropertyPathElement(type)); |
|||
return this; |
|||
} |
|||
|
|||
public PropertyPathBuilder Cast(Type type) |
|||
{ |
|||
_elements.Add(new CastTypePropertyPathElement(type)); |
|||
return this; |
|||
} |
|||
|
|||
public PropertyPath Build() |
|||
{ |
|||
return new PropertyPath(_elements); |
|||
} |
|||
} |
|||
|
|||
public interface IPropertyPathElement |
|||
{ |
|||
|
|||
} |
|||
|
|||
public class PropertyPropertyPathElement : IPropertyPathElement |
|||
{ |
|||
public IPropertyInfo Property { get; } |
|||
|
|||
public PropertyPropertyPathElement(IPropertyInfo property) |
|||
{ |
|||
Property = property; |
|||
} |
|||
} |
|||
|
|||
public class ChildTraversalPropertyPathElement : IPropertyPathElement |
|||
{ |
|||
|
|||
} |
|||
|
|||
public class EnsureTypePropertyPathElement : IPropertyPathElement |
|||
{ |
|||
public Type Type { get; } |
|||
|
|||
public EnsureTypePropertyPathElement(Type type) |
|||
{ |
|||
Type = type; |
|||
} |
|||
} |
|||
|
|||
public class CastTypePropertyPathElement : IPropertyPathElement |
|||
{ |
|||
public CastTypePropertyPathElement(Type type) |
|||
{ |
|||
Type = type; |
|||
} |
|||
|
|||
public Type Type { get; } |
|||
} |
|||
} |
|||
@ -1,262 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Avalonia.Markup.Parsers; |
|||
using XamlX; |
|||
using XamlX.Ast; |
|||
using XamlX.Transform; |
|||
using XamlX.Transform.Transformers; |
|||
using XamlX.TypeSystem; |
|||
using XamlX.Emit; |
|||
using XamlX.IL; |
|||
|
|||
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers |
|||
{ |
|||
class XamlPropertyPathException : XamlTransformException |
|||
{ |
|||
public XamlPropertyPathException(string message, IXamlLineInfo lineInfo, Exception? innerException = null) |
|||
: base(message, lineInfo, innerException) |
|||
{ |
|||
} |
|||
} |
|||
|
|||
class AvaloniaXamlIlPropertyPathTransformer : IXamlAstTransformer |
|||
{ |
|||
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) |
|||
{ |
|||
if (node is XamlAstXamlPropertyValueNode pv |
|||
&& pv.Values.Count == 1 |
|||
&& pv.Values[0] is XamlAstTextNode text |
|||
&& pv.Property.GetClrProperty().Getter?.ReturnType |
|||
.Equals(context.GetAvaloniaTypes().PropertyPath) == true |
|||
) |
|||
{ |
|||
var parentScope = context.ParentNodes().OfType<AvaloniaXamlIlTargetTypeMetadataNode>() |
|||
.FirstOrDefault(); |
|||
if(parentScope == null) |
|||
throw new XamlPropertyPathException("No target type scope found for property path", text); |
|||
if (parentScope.ScopeType != AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style) |
|||
throw new XamlPropertyPathException("PropertyPath is currently only valid for styles", pv); |
|||
|
|||
|
|||
IEnumerable<PropertyPathGrammar.ISyntax> parsed; |
|||
try |
|||
{ |
|||
parsed = PropertyPathGrammar.Parse(text.Text); |
|||
} |
|||
catch (Exception e) |
|||
{ |
|||
throw new XamlPropertyPathException("Unable to parse PropertyPath: " + e.Message, text, innerException: e); |
|||
} |
|||
|
|||
var elements = new List<IXamlIlPropertyPathElementNode>(); |
|||
var currentType = parentScope.TargetType.GetClrType(); |
|||
|
|||
|
|||
var expectProperty = true; |
|||
var expectCast = true; |
|||
var expectTraversal = false; |
|||
var types = context.GetAvaloniaTypes(); |
|||
|
|||
IXamlType GetType(string? ns, string name) |
|||
{ |
|||
return TypeReferenceResolver.ResolveType(context, $"{ns}:{name}", false, |
|||
text, true).GetClrType(); |
|||
} |
|||
|
|||
void HandleProperty(string name, string? typeNamespace, string? typeName) |
|||
{ |
|||
if(!expectProperty || currentType == null) |
|||
throw new XamlPropertyPathException("Unexpected property node", text); |
|||
|
|||
var propertySearchType = |
|||
typeName != null ? GetType(typeNamespace, typeName) : currentType; |
|||
|
|||
IXamlIlPropertyPathElementNode? prop = null; |
|||
var avaloniaPropertyFieldName = name + "Property"; |
|||
var avaloniaPropertyField = propertySearchType.GetAllFields().FirstOrDefault(f => |
|||
f.IsStatic && f.IsPublic && f.Name == avaloniaPropertyFieldName); |
|||
if (avaloniaPropertyField != null) |
|||
{ |
|||
prop = new XamlIlAvaloniaPropertyPropertyPathElementNode(avaloniaPropertyField, |
|||
XamlIlAvaloniaPropertyHelper.GetAvaloniaPropertyType(avaloniaPropertyField, types, text)); |
|||
} |
|||
else |
|||
{ |
|||
var clrProperty = propertySearchType.GetAllProperties().FirstOrDefault(p => p.Name == name); |
|||
if (clrProperty is not null) |
|||
prop = new XamlIClrPropertyPathElementNode(clrProperty); |
|||
} |
|||
|
|||
if (prop == null) |
|||
throw new XamlPropertyPathException( |
|||
$"Unable to resolve property {name} on type {propertySearchType.GetFqn()}", |
|||
text); |
|||
|
|||
currentType = prop.Type; |
|||
elements.Add(prop); |
|||
expectProperty = false; |
|||
expectTraversal = expectCast = true; |
|||
} |
|||
|
|||
foreach (var ge in parsed) |
|||
{ |
|||
if (ge is PropertyPathGrammar.ChildTraversalSyntax) |
|||
{ |
|||
if (!expectTraversal) |
|||
throw new XamlPropertyPathException("Unexpected child traversal .", text); |
|||
elements.Add(new XamlIlChildTraversalPropertyPathElementNode()); |
|||
expectTraversal = expectCast = false; |
|||
expectProperty = true; |
|||
} |
|||
else if (ge is PropertyPathGrammar.EnsureTypeSyntax ets) |
|||
{ |
|||
if(!expectCast) |
|||
throw new XamlPropertyPathException("Unexpected cast node", text); |
|||
currentType = GetType(ets.TypeNamespace, ets.TypeName); |
|||
elements.Add(new XamlIlCastPropertyPathElementNode(currentType, true)); |
|||
expectProperty = false; |
|||
expectCast = expectTraversal = true; |
|||
} |
|||
else if (ge is PropertyPathGrammar.CastTypeSyntax cts) |
|||
{ |
|||
if(!expectCast) |
|||
throw new XamlPropertyPathException("Unexpected cast node", text); |
|||
//TODO: Check if cast can be done
|
|||
currentType = GetType(cts.TypeNamespace, cts.TypeName); |
|||
elements.Add(new XamlIlCastPropertyPathElementNode(currentType, false)); |
|||
expectProperty = false; |
|||
expectCast = expectTraversal = true; |
|||
} |
|||
else if (ge is PropertyPathGrammar.PropertySyntax ps) |
|||
{ |
|||
HandleProperty(ps.Name, null, null); |
|||
} |
|||
else if (ge is PropertyPathGrammar.TypeQualifiedPropertySyntax tqps) |
|||
{ |
|||
HandleProperty(tqps.Name, tqps.TypeNamespace, tqps.TypeName); |
|||
} |
|||
else |
|||
throw new XamlPropertyPathException("Unexpected node " + ge, text); |
|||
|
|||
} |
|||
var propertyPathNode = new XamlIlPropertyPathNode(text, elements, types); |
|||
if (propertyPathNode.Type == null) |
|||
throw new XamlPropertyPathException("Unexpected end of the property path", text); |
|||
pv.Values[0] = propertyPathNode; |
|||
} |
|||
|
|||
return node; |
|||
} |
|||
|
|||
interface IXamlIlPropertyPathElementNode |
|||
{ |
|||
void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen); |
|||
IXamlType? Type { get; } |
|||
} |
|||
|
|||
class XamlIlChildTraversalPropertyPathElementNode : IXamlIlPropertyPathElementNode |
|||
{ |
|||
public void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) |
|||
=> codeGen.EmitCall( |
|||
context.GetAvaloniaTypes() |
|||
.PropertyPathBuilder.GetMethod(m => m.Name == "ChildTraversal")); |
|||
|
|||
public IXamlType? Type => null; |
|||
} |
|||
|
|||
class XamlIlAvaloniaPropertyPropertyPathElementNode : IXamlIlPropertyPathElementNode |
|||
{ |
|||
private readonly IXamlField _field; |
|||
|
|||
public XamlIlAvaloniaPropertyPropertyPathElementNode(IXamlField field, IXamlType propertyType) |
|||
{ |
|||
_field = field; |
|||
Type = propertyType; |
|||
} |
|||
|
|||
public void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) |
|||
=> codeGen |
|||
.Ldsfld(_field) |
|||
.EmitCall(context.GetAvaloniaTypes() |
|||
.PropertyPathBuilder.GetMethod(m => m.Name == "Property")); |
|||
|
|||
public IXamlType Type { get; } |
|||
} |
|||
|
|||
class XamlIClrPropertyPathElementNode : IXamlIlPropertyPathElementNode |
|||
{ |
|||
private readonly IXamlProperty _property; |
|||
|
|||
public XamlIClrPropertyPathElementNode(IXamlProperty property) |
|||
{ |
|||
_property = property; |
|||
} |
|||
|
|||
public void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) |
|||
{ |
|||
context.Configuration.GetExtra<XamlIlClrPropertyInfoEmitter>() |
|||
.Emit(context, codeGen, _property); |
|||
|
|||
codeGen.EmitCall(context.GetAvaloniaTypes() |
|||
.PropertyPathBuilder.GetMethod(m => m.Name == "Property")); |
|||
} |
|||
|
|||
public IXamlType Type => _property.PropertyType; |
|||
} |
|||
|
|||
class XamlIlCastPropertyPathElementNode : IXamlIlPropertyPathElementNode |
|||
{ |
|||
private readonly IXamlType _type; |
|||
private readonly bool _ensureType; |
|||
|
|||
public XamlIlCastPropertyPathElementNode(IXamlType type, bool ensureType) |
|||
{ |
|||
_type = type; |
|||
_ensureType = ensureType; |
|||
} |
|||
|
|||
public void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) |
|||
{ |
|||
codeGen |
|||
.Ldtype(_type) |
|||
.EmitCall(context.GetAvaloniaTypes() |
|||
.PropertyPathBuilder.GetMethod(m => m.Name == (_ensureType ? "EnsureType" : "Cast"))); |
|||
} |
|||
|
|||
public IXamlType Type => _type; |
|||
} |
|||
|
|||
class XamlIlPropertyPathNode : XamlAstNode, IXamlIlPropertyPathNode, IXamlAstEmitableNode<IXamlILEmitter, XamlILNodeEmitResult> |
|||
{ |
|||
private readonly List<IXamlIlPropertyPathElementNode> _elements; |
|||
private readonly AvaloniaXamlIlWellKnownTypes _types; |
|||
|
|||
public XamlIlPropertyPathNode(IXamlLineInfo lineInfo, |
|||
List<IXamlIlPropertyPathElementNode> elements, |
|||
AvaloniaXamlIlWellKnownTypes types) : base(lineInfo) |
|||
{ |
|||
_elements = elements; |
|||
_types = types; |
|||
Type = new XamlAstClrTypeReference(this, types.PropertyPath, false); |
|||
} |
|||
|
|||
public IXamlAstTypeReference Type { get; } |
|||
public IXamlType? PropertyType => _elements.LastOrDefault()?.Type; |
|||
public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) |
|||
{ |
|||
codeGen |
|||
.Newobj(_types.PropertyPathBuilder.GetConstructor()); |
|||
foreach(var e in _elements) |
|||
e.Emit(context, codeGen); |
|||
codeGen.EmitCall(_types.PropertyPathBuilder.GetMethod(m => m.Name == "Build")); |
|||
return XamlILNodeEmitResult.Type(0, _types.PropertyPath); |
|||
} |
|||
} |
|||
} |
|||
|
|||
interface IXamlIlPropertyPathNode : IXamlAstValueNode |
|||
{ |
|||
IXamlType? PropertyType { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System; |
|||
using XamlX; |
|||
using XamlX.Ast; |
|||
|
|||
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers |
|||
{ |
|||
internal class XamlPropertyPathException : XamlTransformException |
|||
{ |
|||
public XamlPropertyPathException(string message, IXamlLineInfo lineInfo, Exception? innerException = null) |
|||
: base(message, lineInfo, innerException) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue