diff --git a/src/Framework/Framework/Compilation/ControlTree/IAbstractDirectiveAttributeReference.cs b/src/Framework/Framework/Compilation/ControlTree/IAbstractDirectiveAttributeReference.cs index fb651ef4c1..775cbb69da 100644 --- a/src/Framework/Framework/Compilation/ControlTree/IAbstractDirectiveAttributeReference.cs +++ b/src/Framework/Framework/Compilation/ControlTree/IAbstractDirectiveAttributeReference.cs @@ -15,7 +15,7 @@ public interface IAbstractDirectiveAttributeReference { TypeReferenceBindingParserNode TypeSyntax { get; } IdentifierNameBindingParserNode NameSyntax { get; } - LiteralExpressionBindingParserNode Initializer { get; } + BindingParserNode Initializer { get; } ITypeDescriptor? Type { get; } } } diff --git a/src/Framework/Framework/Compilation/ControlTree/IAbstractTreeBuilder.cs b/src/Framework/Framework/Compilation/ControlTree/IAbstractTreeBuilder.cs index 32f2edaac7..d94cfbb444 100644 --- a/src/Framework/Framework/Compilation/ControlTree/IAbstractTreeBuilder.cs +++ b/src/Framework/Framework/Compilation/ControlTree/IAbstractTreeBuilder.cs @@ -29,7 +29,7 @@ public interface IAbstractTreeBuilder IAbstractViewModuleDirective BuildViewModuleDirective(DothtmlDirectiveNode directiveNode, string modulePath, string resourceName); IAbstractPropertyDeclarationDirective BuildPropertyDeclarationDirective(DothtmlDirectiveNode directive, TypeReferenceBindingParserNode typeSyntax, SimpleNameBindingParserNode nameSyntax, BindingParserNode? initializer, IList resolvedAttributes, BindingParserNode valueSyntaxRoot, ImmutableList imports); - IAbstractDirectiveAttributeReference BuildPropertyDeclarationAttributeReference(DothtmlDirectiveNode directiveNode, IdentifierNameBindingParserNode propertyNameSyntax, TypeReferenceBindingParserNode typeSyntax, LiteralExpressionBindingParserNode initializer, ImmutableList imports); + IAbstractDirectiveAttributeReference BuildPropertyDeclarationAttributeReference(DothtmlDirectiveNode directiveNode, IdentifierNameBindingParserNode propertyNameSyntax, TypeReferenceBindingParserNode typeSyntax, BindingParserNode initializer, ImmutableList imports); IAbstractPropertyBinding BuildPropertyBinding(IPropertyDescriptor property, IAbstractBinding binding, DothtmlAttributeNode? sourceAttributeNode); IAbstractPropertyControl BuildPropertyControl(IPropertyDescriptor property, IAbstractControl? control, DothtmlElementNode? wrapperElementNode); diff --git a/src/Framework/Framework/Compilation/ControlTree/Resolved/ResolvedPropertyDeclarationDirective.cs b/src/Framework/Framework/Compilation/ControlTree/Resolved/ResolvedPropertyDeclarationDirective.cs index 33212d3832..7223d794b1 100644 --- a/src/Framework/Framework/Compilation/ControlTree/Resolved/ResolvedPropertyDeclarationDirective.cs +++ b/src/Framework/Framework/Compilation/ControlTree/Resolved/ResolvedPropertyDeclarationDirective.cs @@ -62,7 +62,7 @@ private IEnumerable InstantiateAttributes(DothtmlDirectiveNode dothtmlDi (name, attributes) => { var attributeType = (attributes.First().Type as ResolvedTypeDescriptor)?.Type; - var properties = attributes.Select(a => (name: a.NameSyntax.Name, value: a.Initializer.Value)); + var properties = attributes.Select(a => (name: a.NameSyntax.Name, value: (a.Initializer as LiteralExpressionBindingParserNode)?.Value ?? "")); return (attributeType, properties); }).ToList(); diff --git a/src/Framework/Framework/Compilation/ControlTree/Resolved/ResolvedPropertyDirectiveAttributeReference.cs b/src/Framework/Framework/Compilation/ControlTree/Resolved/ResolvedPropertyDirectiveAttributeReference.cs index 652789071f..bf12ce5b2d 100644 --- a/src/Framework/Framework/Compilation/ControlTree/Resolved/ResolvedPropertyDirectiveAttributeReference.cs +++ b/src/Framework/Framework/Compilation/ControlTree/Resolved/ResolvedPropertyDirectiveAttributeReference.cs @@ -15,14 +15,14 @@ public class ResolvedPropertyDirectiveAttributeReference : IAbstractDirectiveAtt public TypeReferenceBindingParserNode TypeSyntax { get; } public IdentifierNameBindingParserNode NameSyntax { get; } public ITypeDescriptor? Type { get; set; } - public LiteralExpressionBindingParserNode Initializer { get; } + public BindingParserNode Initializer { get; } public ResolvedPropertyDirectiveAttributeReference( DirectiveCompilationService directiveService, DothtmlDirectiveNode directiveNode, TypeReferenceBindingParserNode typeReferenceBindingParserNode, IdentifierNameBindingParserNode attributePropertyNameReference, - LiteralExpressionBindingParserNode initializer, + BindingParserNode initializer, ImmutableList imports) { DirectiveNode = directiveNode; diff --git a/src/Framework/Framework/Compilation/ControlTree/Resolved/ResolvedTreeBuilder.cs b/src/Framework/Framework/Compilation/ControlTree/Resolved/ResolvedTreeBuilder.cs index ff47d82790..d8d50120f2 100644 --- a/src/Framework/Framework/Compilation/ControlTree/Resolved/ResolvedTreeBuilder.cs +++ b/src/Framework/Framework/Compilation/ControlTree/Resolved/ResolvedTreeBuilder.cs @@ -114,7 +114,7 @@ public IAbstractDirectiveAttributeReference BuildPropertyDeclarationAttributeRef DothtmlDirectiveNode directiveNode, IdentifierNameBindingParserNode propertyNameSyntax, TypeReferenceBindingParserNode typeSyntax, - LiteralExpressionBindingParserNode initializer, + BindingParserNode initializer, ImmutableList imports) { return new ResolvedPropertyDirectiveAttributeReference(directiveService, directiveNode, typeSyntax, propertyNameSyntax, initializer, imports); diff --git a/src/Framework/Framework/Compilation/Directives/PropertyDeclarationDirectiveCompiler.cs b/src/Framework/Framework/Compilation/Directives/PropertyDeclarationDirectiveCompiler.cs index 302a1c472f..2d554c2950 100644 --- a/src/Framework/Framework/Compilation/Directives/PropertyDeclarationDirectiveCompiler.cs +++ b/src/Framework/Framework/Compilation/Directives/PropertyDeclarationDirectiveCompiler.cs @@ -77,11 +77,11 @@ private AttributeInfo GetAttributeInfo(BindingParserNode attributeReference, Dot return new AttributeInfo( typeRef, new SimpleNameBindingParserNode("") { StartPosition = attributeReference.EndPosition }, - new LiteralExpressionBindingParserNode("") { StartPosition = attributeReference.EndPosition }); + new SimpleNameBindingParserNode("") { StartPosition = attributeReference.EndPosition }); } var attributePropertyReference = assignment.FirstExpression as MemberAccessBindingParserNode; - var initializer = assignment.SecondExpression as LiteralExpressionBindingParserNode; + var initializer = assignment.SecondExpression; var attributeTypeReference = attributePropertyReference?.TargetExpression; var attributePropertyNameReference = attributePropertyReference?.MemberNameExpression; @@ -93,10 +93,9 @@ private AttributeInfo GetAttributeInfo(BindingParserNode attributeReference, Dot attributeTypeReference = attributeTypeReference ?? new SimpleNameBindingParserNode(""); attributePropertyNameReference = attributePropertyNameReference ?? new SimpleNameBindingParserNode("") { StartPosition = attributeTypeReference.EndPosition }; } - if (initializer == null) + if (assignment.SecondExpression is not LiteralExpressionBindingParserNode) { directiveNode.AddError($"Value for property {attributeTypeReference.ToDisplayString()} of attribute {attributePropertyNameReference.ToDisplayString()} is missing or not a constant."); - initializer = new LiteralExpressionBindingParserNode("") { StartPosition = attributePropertyNameReference.EndPosition }; } var type = new ActualTypeReferenceBindingParserNode(attributeTypeReference); @@ -120,7 +119,7 @@ protected override ImmutableList CreateArtefact(IReadOnlyList AssertEx.BindingNode(node, expectedDisplayString, start, length, hasErrors); private static string SkipWhitespaces(string str) => string.Join("", str.Where(c => !char.IsWhiteSpace(c))); diff --git a/src/Tests/Runtime/ControlTree/DefaultControlTreeResolver/PropertyDirectiveTests.cs b/src/Tests/Runtime/ControlTree/DefaultControlTreeResolver/PropertyDirectiveTests.cs index 21330ae2be..1128d1f66e 100644 --- a/src/Tests/Runtime/ControlTree/DefaultControlTreeResolver/PropertyDirectiveTests.cs +++ b/src/Tests/Runtime/ControlTree/DefaultControlTreeResolver/PropertyDirectiveTests.cs @@ -22,6 +22,11 @@ @viewModel object Assert.AreEqual("MyProperty", property.NameSyntax.Name); Assert.AreEqual(4, property.Attributes.Count); + + AssertEx.BindingNode(property.Attributes[0].Initializer, "", 19, 0); + AssertEx.BindingNode(property.Attributes[1].Initializer, "", 28, 0); + AssertEx.BindingNode(property.Attributes[2].Initializer, "", 42, 1, true); + AssertEx.BindingNode(property.Attributes[3].Initializer, "t", 104, 2); } [TestMethod] @@ -45,7 +50,7 @@ @viewModel object } [TestMethod] - public void ResolvedTree_PropertyDirectiveArrayInicializer_ResolvedCorrectly() + public void ResolvedTree_PropertyDirectiveInvalidArrayInicializer_ResolvedCorrectly() { var root = ParseSource(@$" @viewModel object @@ -53,11 +58,29 @@ @viewModel object var property = root.Directives["property"].SingleOrDefault() as IAbstractPropertyDeclarationDirective; - var nodes = property.InitializerSyntax.EnumerateChildNodes(); + Assert.AreEqual("System.String", property.PropertyType.FullName); + Assert.AreEqual("a", property.NameSyntax.Name); + var nodes = property.InitializerSyntax.EnumerateChildNodes(); Assert.IsFalse(nodes.Any(n => n == property.InitializerSyntax)); + } + + [TestMethod] + public void ResolvedTree_PropertyDirectiveArrayInicializerAndAttributes_ResolvedCorrectly() + { + var root = ParseSource(""" +@viewModel object +@property string[] MyProperty=["",""], MarkupOptionsAttribute.Required = true, MarkupOptionsAttribute.AllowBinding = false +"""); + + var property = root.Directives["property"].SingleOrDefault() as IAbstractPropertyDeclarationDirective; + + Assert.AreEqual("System.String[]", property.PropertyType.FullName); + Assert.AreEqual("MyProperty", property.NameSyntax.Name); - Assert.AreEqual(2,nodes.Count()); + Assert.AreEqual(2, property.Attributes.Count); + AssertEx.BindingNode(property.Attributes[0].Initializer, "True", 62, 5); + AssertEx.BindingNode(property.Attributes[1].Initializer, "False", 106, 6); } } }