Browse Source

Fix namescope searching to recursively search parent namescopes up to the root namescope and never find a name in a namescope that is not a direct ancestor of the current namescope.

pull/3001/head
Jeremy Koritzinsky 7 years ago
parent
commit
0ca00d5f75
  1. 72
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs
  2. 3
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlMetadataRemover.cs
  3. 46
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlBindingPathHelper.cs

72
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs

@ -10,42 +10,49 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
{
if (node is XamlIlPropertyAssignmentNode pa
&& pa.Property.Name == "Name"
&& pa.Property.DeclaringType.FullName == "Avalonia.StyledElement")
if (node is XamlIlPropertyAssignmentNode pa)
{
if (context.ParentNodes().FirstOrDefault() is XamlIlManipulationGroupNode mg
&& mg.Children.OfType<ScopeRegistrationNode>().Any())
return node;
if (pa.Property.Name == "Name"
&& pa.Property.DeclaringType.FullName == "Avalonia.StyledElement")
{
if (context.ParentNodes().FirstOrDefault() is XamlIlManipulationGroupNode mg
&& mg.Children.OfType<ScopeRegistrationNode>().Any())
return node;
IXamlIlAstValueNode value = null;
for (var c = 0; c < pa.Values.Count; c++)
if (pa.Values[c].Type.GetClrType().Equals(context.Configuration.WellKnownTypes.String))
{
value = pa.Values[c];
if (!(value is XamlIlAstTextNode))
IXamlIlAstValueNode value = null;
for (var c = 0; c < pa.Values.Count; c++)
if (pa.Values[c].Type.GetClrType().Equals(context.Configuration.WellKnownTypes.String))
{
var local = new XamlIlAstCompilerLocalNode(value);
// Wrap original in local initialization
pa.Values[c] = new XamlIlAstLocalInitializationNodeEmitter(value, value, local);
// Use local
value = local;
}
value = pa.Values[c];
if (!(value is XamlIlAstTextNode))
{
var local = new XamlIlAstCompilerLocalNode(value);
// Wrap original in local initialization
pa.Values[c] = new XamlIlAstLocalInitializationNodeEmitter(value, value, local);
// Use local
value = local;
}
break;
}
break;
}
if (value != null)
{
var objectType = context.ParentNodes().OfType<XamlIlAstObjectNode>().FirstOrDefault()?.Type.GetClrType();
return new XamlIlManipulationGroupNode(pa)
if (value != null)
{
Children =
var objectType = context.ParentNodes().OfType<XamlIlAstObjectNode>().FirstOrDefault()?.Type.GetClrType();
return new XamlIlManipulationGroupNode(pa)
{
pa,
new ScopeRegistrationNode(value, objectType)
}
};
Children =
{
pa,
new ScopeRegistrationNode(value, objectType)
}
};
}
}
else if (pa.Property.CustomAttributes.Select(attr => attr.Type).Intersect(context.Configuration.TypeMappings.DeferredContentPropertyAttributes).Any())
{
pa.Values[pa.Values.Count - 1] =
new NestedScopeMetadataNode(pa.Values[pa.Values.Count - 1]);
}
}
@ -53,6 +60,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
}
}
class NestedScopeMetadataNode : XamlIlValueWithSideEffectNodeBase
{
public NestedScopeMetadataNode(IXamlIlAstValueNode value) : base(value, value)
{
}
}
class ScopeRegistrationNode : XamlIlAstNode, IXamlIlAstManipulationNode, IXamlIlAstEmitableNode
{
public IXamlIlAstValueNode Value { get; set; }

3
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlMetadataRemover.cs

@ -14,6 +14,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
if (node is AvaloniaXamlIlDataContextTypeMetadataNode dataContextTypeMetadata)
return dataContextTypeMetadata.Value;
if (node is NestedScopeMetadataNode nestedScope)
return nestedScope.Value;
return node;
}
}

46
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlBindingPathHelper.cs

@ -180,7 +180,20 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
nodes.Add(new FindAncestorPathElementNode(GetType(ancestor.Namespace, ancestor.TypeName), ancestor.Level));
break;
case BindingExpressionGrammar.NameNode elementName:
var elementType = ScopeRegistrationFinder.GetControlType(context, context.RootObject, elementName.Name);
IXamlIlType elementType = null;
foreach (var deferredContent in context.ParentNodes().OfType<NestedScopeMetadataNode>())
{
elementType = ScopeRegistrationFinder.GetControlType(deferredContent, elementName.Name);
if (!(elementType is null))
{
break;
}
}
if (elementType is null)
{
elementType = ScopeRegistrationFinder.GetControlType(context.RootObject, elementName.Name);
}
if (elementType is null)
{
throw new XamlIlParseException($"Unable to find element '{elementName.Name}' in the current namescope. Unable to use a compiled binding with a name binding if the name cannot be found at compile time.", lineInfo);
@ -199,8 +212,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
}
}
class ScopeRegistrationFinder : IXamlIlAstTransformer
class ScopeRegistrationFinder : IXamlIlAstVisitor
{
private Stack<IXamlIlAstNode> _stack = new Stack<IXamlIlAstNode>();
private Stack<IXamlIlAstNode> _childScopesStack = new Stack<IXamlIlAstNode>();
private ScopeRegistrationFinder(string name)
{
Name = name;
@ -210,16 +226,34 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
IXamlIlType ControlType { get; set; }
public static IXamlIlType GetControlType(XamlIlAstTransformationContext context, IXamlIlAstNode namescopeRoot, string name)
public static IXamlIlType GetControlType(IXamlIlAstNode namescopeRoot, string name)
{
var finder = new ScopeRegistrationFinder(name);
context.Visit(namescopeRoot, finder);
namescopeRoot.Visit(finder);
return finder.ControlType;
}
IXamlIlAstNode IXamlIlAstTransformer.Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
void IXamlIlAstVisitor.Pop()
{
var node = _stack.Pop();
if (_childScopesStack.Count > 0 && node == _childScopesStack.Peek())
{
_childScopesStack.Pop();
}
}
void IXamlIlAstVisitor.Push(IXamlIlAstNode node)
{
_stack.Push(node);
if (node is NestedScopeMetadataNode)
{
_childScopesStack.Push(node);
}
}
IXamlIlAstNode IXamlIlAstVisitor.Visit(IXamlIlAstNode node)
{
if (node is ScopeRegistrationNode registration)
if (_childScopesStack.Count == 0 && node is ScopeRegistrationNode registration)
{
if (registration.Value is XamlIlAstTextNode text && text.Text == Name)
{

Loading…
Cancel
Save