From c22286d491eebf418d4cab05ba84a1cc8ecbb598 Mon Sep 17 00:00:00 2001 From: Stephane Delcroix Date: Wed, 28 Jun 2023 11:50:51 +0200 Subject: [PATCH] [X] x:Type and x:Static don't expand to Extension - fixes #11833 --- .../StaticExtension.cs | 2 +- .../CompiledMarkupExtensions/TypeExtension.cs | 2 +- .../src/Build.Tasks/XmlTypeExtensions.cs | 16 +++++++++--- src/Controls/src/Core/IXamlTypeResolver.cs | 1 + .../net-android/PublicAPI.Unshipped.txt | 1 + .../PublicAPI/net-ios/PublicAPI.Unshipped.txt | 1 + .../net-maccatalyst/PublicAPI.Unshipped.txt | 1 + .../net-tizen/PublicAPI.Unshipped.txt | 1 + .../net-windows/PublicAPI.Unshipped.txt | 1 + .../PublicAPI/net/PublicAPI.Unshipped.txt | 1 + .../netstandard/PublicAPI.Unshipped.txt | 1 + .../src/Xaml/ApplyPropertiesVisitor.cs | 2 +- src/Controls/src/Xaml/CreateValuesVisitor.cs | 2 +- .../Xaml/MarkupExtensions/StaticExtension.cs | 2 +- .../Xaml/MarkupExtensions/TypeExtension.cs | 2 +- src/Controls/src/Xaml/XamlParser.cs | 6 ++--- src/Controls/src/Xaml/XamlServiceProvider.cs | 15 ++++++----- .../src/Xaml/XmlTypeXamlExtensions.cs | 5 ++-- .../Xaml.UnitTests/Issues/Maui11833.xaml | 11 ++++++++ .../Xaml.UnitTests/Issues/Maui11833.xaml.cs | 25 +++++++++++++++++++ .../tests/Xaml.UnitTests/LoaderTests.cs | 2 +- .../Xaml.UnitTests/TypeExtensionTests.cs | 7 ++++++ 22 files changed, 85 insertions(+), 22 deletions(-) create mode 100644 src/Controls/tests/Xaml.UnitTests/Issues/Maui11833.xaml create mode 100644 src/Controls/tests/Xaml.UnitTests/Issues/Maui11833.xaml.cs diff --git a/src/Controls/src/Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs b/src/Controls/src/Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs index 76d23cffc4ac..598c5a723fdc 100644 --- a/src/Controls/src/Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs +++ b/src/Controls/src/Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs @@ -24,7 +24,7 @@ public IEnumerable ProvideValue(IElementNode node, ModuleDefinition var typename = member.Substring(0, dotIdx); var membername = member.Substring(dotIdx + 1); - var typeRef = module.ImportReference(XmlTypeExtensions.GetTypeReference(context.Cache, typename, module, node as BaseNode)); + var typeRef = module.ImportReference(XmlTypeExtensions.GetTypeReference(context.Cache, typename, false, module, node as BaseNode)); var fieldRef = GetFieldReference(context.Cache, typeRef, membername, module); var propertyDef = GetPropertyDefinition(context.Cache, typeRef, membername, module); diff --git a/src/Controls/src/Build.Tasks/CompiledMarkupExtensions/TypeExtension.cs b/src/Controls/src/Build.Tasks/CompiledMarkupExtensions/TypeExtension.cs index add45a05eea9..fb727c73e2b3 100644 --- a/src/Controls/src/Build.Tasks/CompiledMarkupExtensions/TypeExtension.cs +++ b/src/Controls/src/Build.Tasks/CompiledMarkupExtensions/TypeExtension.cs @@ -28,7 +28,7 @@ public IEnumerable ProvideValue(IElementNode node, ModuleDefinition node.CollectionItems.Clear(); } - var typeref = module.ImportReference(XmlTypeExtensions.GetTypeReference(context.Cache, valueNode.Value as string, module, node as BaseNode)); + var typeref = module.ImportReference(XmlTypeExtensions.GetTypeReference(context.Cache, valueNode.Value as string, false, module, node as BaseNode)); context.TypeExtensions[node] = typeref ?? throw new BuildException(BuildExceptionCode.TypeResolution, node as IXmlLineInfo, null, valueNode.Value); diff --git a/src/Controls/src/Build.Tasks/XmlTypeExtensions.cs b/src/Controls/src/Build.Tasks/XmlTypeExtensions.cs index 57dfee10f62c..6d3a1538d814 100644 --- a/src/Controls/src/Build.Tasks/XmlTypeExtensions.cs +++ b/src/Controls/src/Build.Tasks/XmlTypeExtensions.cs @@ -49,8 +49,10 @@ static IList GatherXmlnsDefinitionAttributes(ModuleDef return xmlnsDefinitions; } - public static TypeReference GetTypeReference(XamlCache cache, string xmlType, ModuleDefinition module, BaseNode node) + => GetTypeReference(cache, xmlType, true, module, node); + + public static TypeReference GetTypeReference(XamlCache cache, string xmlType, bool tryExtensionFirst, ModuleDefinition module, BaseNode node) { var split = xmlType.Split(':'); if (split.Length > 2) @@ -68,7 +70,7 @@ public static TypeReference GetTypeReference(XamlCache cache, string xmlType, Mo name = split[0]; } var namespaceuri = node.NamespaceResolver.LookupNamespace(prefix) ?? ""; - return GetTypeReference(new XmlType(namespaceuri, name, null), cache, module, node as IXmlLineInfo); + return GetTypeReference(new XmlType(namespaceuri, name, null), tryExtensionFirst, cache, module, node as IXmlLineInfo); } public static TypeReference GetTypeReference(XamlCache cache, string namespaceURI, string typename, ModuleDefinition module, IXmlLineInfo xmlInfo) @@ -77,6 +79,9 @@ public static TypeReference GetTypeReference(XamlCache cache, string namespaceUR } public static bool TryGetTypeReference(this XmlType xmlType, XamlCache cache, ModuleDefinition module, IXmlLineInfo xmlInfo, out TypeReference typeReference) + => TryGetTypeReference(xmlType, true, cache, module, xmlInfo, out typeReference); + + public static bool TryGetTypeReference(this XmlType xmlType, bool tryExtensionFirst, XamlCache cache, ModuleDefinition module, IXmlLineInfo xmlInfo, out TypeReference typeReference) { IList xmlnsDefinitions = cache.GetXmlsDefinitions(module, GatherXmlnsDefinitionAttributes); @@ -89,7 +94,7 @@ public static bool TryGetTypeReference(this XmlType xmlType, XamlCache cache, Mo if (type is not null && type.IsPublicOrVisibleInternal(module)) return type; return null; - }); + }, tryExtensionFirst); if (type != null && typeArguments != null && type.HasGenericParameters) type = module.ImportReference(type).MakeGenericInstanceType(typeArguments.Select(x => x.GetTypeReference(cache, module, xmlInfo)).ToArray()); @@ -98,8 +103,11 @@ public static bool TryGetTypeReference(this XmlType xmlType, XamlCache cache, Mo } public static TypeReference GetTypeReference(this XmlType xmlType, XamlCache cache, ModuleDefinition module, IXmlLineInfo xmlInfo) + => GetTypeReference(xmlType, true, cache, module, xmlInfo); + + public static TypeReference GetTypeReference(this XmlType xmlType, bool tryExtensionFirst, XamlCache cache, ModuleDefinition module, IXmlLineInfo xmlInfo) { - if (TryGetTypeReference(xmlType, cache, module, xmlInfo, out TypeReference typeReference)) + if (TryGetTypeReference(xmlType, tryExtensionFirst, cache, module, xmlInfo, out TypeReference typeReference)) return typeReference; throw new BuildException(BuildExceptionCode.TypeResolution, xmlInfo, null, $"{xmlType.NamespaceUri}:{xmlType.Name}"); diff --git a/src/Controls/src/Core/IXamlTypeResolver.cs b/src/Controls/src/Core/IXamlTypeResolver.cs index 49c3e175d499..d19766fb0b01 100644 --- a/src/Controls/src/Core/IXamlTypeResolver.cs +++ b/src/Controls/src/Core/IXamlTypeResolver.cs @@ -6,6 +6,7 @@ namespace Microsoft.Maui.Controls.Xaml public interface IXamlTypeResolver { Type Resolve(string qualifiedTypeName, IServiceProvider serviceProvider = null); + Type Resolve(string qualifiedTypeName, bool tryExtensionFirst, IServiceProvider serviceProvider = null); bool TryResolve(string qualifiedTypeName, out Type type); } } \ No newline at end of file diff --git a/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt index c09743196b38..613d0cd3dedd 100644 --- a/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt @@ -1,5 +1,6 @@ #nullable enable *REMOVED*override Microsoft.Maui.Controls.RefreshView.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size +~Microsoft.Maui.Controls.Xaml.IXamlTypeResolver.Resolve(string qualifiedTypeName, bool tryExtensionFirst, System.IServiceProvider serviceProvider = null) -> System.Type Microsoft.Maui.Controls.Border.~Border() -> void Microsoft.Maui.Controls.IWindowCreator Microsoft.Maui.Controls.IWindowCreator.CreateWindow(Microsoft.Maui.Controls.Application! app, Microsoft.Maui.IActivationState? activationState) -> Microsoft.Maui.Controls.Window! diff --git a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt index 735b73a38ff3..74834a959b92 100644 --- a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt @@ -32,6 +32,7 @@ static Microsoft.Maui.Controls.Shapes.Matrix.operator ==(Microsoft.Maui.Controls override Microsoft.Maui.Controls.View.ChangeVisualState() -> void Microsoft.Maui.Controls.Handlers.BoxViewHandler Microsoft.Maui.Controls.Handlers.BoxViewHandler.BoxViewHandler() -> void +~Microsoft.Maui.Controls.Xaml.IXamlTypeResolver.Resolve(string qualifiedTypeName, bool tryExtensionFirst, System.IServiceProvider serviceProvider = null) -> System.Type ~override Microsoft.Maui.Controls.Handlers.Items.CarouselViewController.DetermineCellReuseId(Foundation.NSIndexPath indexPath) -> string ~override Microsoft.Maui.Controls.ImageButton.OnPropertyChanged(string propertyName = null) -> void ~override Microsoft.Maui.Controls.Handlers.Compatibility.PhoneFlyoutPageRenderer.ViewWillTransitionToSize(CoreGraphics.CGSize toSize, UIKit.IUIViewControllerTransitionCoordinator coordinator) -> void diff --git a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt index 735b73a38ff3..093d3303572f 100644 --- a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt @@ -1,5 +1,6 @@ #nullable enable *REMOVED*override Microsoft.Maui.Controls.RefreshView.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size +~Microsoft.Maui.Controls.Xaml.IXamlTypeResolver.Resolve(string qualifiedTypeName, bool tryExtensionFirst, System.IServiceProvider serviceProvider = null) -> System.Type Microsoft.Maui.Controls.Border.~Border() -> void Microsoft.Maui.Controls.IWindowCreator Microsoft.Maui.Controls.IWindowCreator.CreateWindow(Microsoft.Maui.Controls.Application! app, Microsoft.Maui.IActivationState? activationState) -> Microsoft.Maui.Controls.Window! diff --git a/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt index 59345b33b394..a776ee6c7e61 100644 --- a/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt @@ -1,4 +1,5 @@ #nullable enable +~Microsoft.Maui.Controls.Xaml.IXamlTypeResolver.Resolve(string qualifiedTypeName, bool tryExtensionFirst, System.IServiceProvider serviceProvider = null) -> System.Type Microsoft.Maui.Controls.Border.~Border() -> void Microsoft.Maui.Controls.IWindowCreator Microsoft.Maui.Controls.IWindowCreator.CreateWindow(Microsoft.Maui.Controls.Application! app, Microsoft.Maui.IActivationState? activationState) -> Microsoft.Maui.Controls.Window! diff --git a/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt index 4f17f691caa8..2b8978fc8137 100644 --- a/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt @@ -1,5 +1,6 @@ #nullable enable *REMOVED*override Microsoft.Maui.Controls.RefreshView.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size +~Microsoft.Maui.Controls.Xaml.IXamlTypeResolver.Resolve(string qualifiedTypeName, bool tryExtensionFirst, System.IServiceProvider serviceProvider = null) -> System.Type Microsoft.Maui.Controls.Border.~Border() -> void Microsoft.Maui.Controls.IWindowCreator Microsoft.Maui.Controls.IWindowCreator.CreateWindow(Microsoft.Maui.Controls.Application! app, Microsoft.Maui.IActivationState? activationState) -> Microsoft.Maui.Controls.Window! diff --git a/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt index 4d3df32a7b67..3d6a571705ea 100644 --- a/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt @@ -1,5 +1,6 @@ #nullable enable *REMOVED*override Microsoft.Maui.Controls.RefreshView.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size +~Microsoft.Maui.Controls.Xaml.IXamlTypeResolver.Resolve(string qualifiedTypeName, bool tryExtensionFirst, System.IServiceProvider serviceProvider = null) -> System.Type Microsoft.Maui.Controls.Border.~Border() -> void Microsoft.Maui.Controls.IWindowCreator Microsoft.Maui.Controls.IWindowCreator.CreateWindow(Microsoft.Maui.Controls.Application! app, Microsoft.Maui.IActivationState? activationState) -> Microsoft.Maui.Controls.Window! diff --git a/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt index 12b6149e4df5..8633ac233a2a 100644 --- a/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt @@ -1,5 +1,6 @@ #nullable enable *REMOVED*override Microsoft.Maui.Controls.RefreshView.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size +~Microsoft.Maui.Controls.Xaml.IXamlTypeResolver.Resolve(string qualifiedTypeName, bool tryExtensionFirst, System.IServiceProvider serviceProvider = null) -> System.Type Microsoft.Maui.Controls.Border.~Border() -> void Microsoft.Maui.Controls.IWindowCreator Microsoft.Maui.Controls.IWindowCreator.CreateWindow(Microsoft.Maui.Controls.Application! app, Microsoft.Maui.IActivationState? activationState) -> Microsoft.Maui.Controls.Window! diff --git a/src/Controls/src/Xaml/ApplyPropertiesVisitor.cs b/src/Controls/src/Xaml/ApplyPropertiesVisitor.cs index 89d0b88f5330..527f2cfdc6ec 100644 --- a/src/Controls/src/Xaml/ApplyPropertiesVisitor.cs +++ b/src/Controls/src/Xaml/ApplyPropertiesVisitor.cs @@ -316,7 +316,7 @@ static bool GetRealNameAndType(ref Type elementType, string namespaceURI, ref st var typename = localname.Substring(0, dotIdx); localname = localname.Substring(dotIdx + 1); XamlParseException xpe; - elementType = XamlParser.GetElementType(new XmlType(namespaceURI, typename, null), lineInfo, + elementType = XamlParser.GetElementType(new XmlType(namespaceURI, typename, null), true, lineInfo, rootElement.GetType().Assembly, out xpe); if (xpe != null) diff --git a/src/Controls/src/Xaml/CreateValuesVisitor.cs b/src/Controls/src/Xaml/CreateValuesVisitor.cs index fb0f298f4d59..2f59e2cd6a01 100644 --- a/src/Controls/src/Xaml/CreateValuesVisitor.cs +++ b/src/Controls/src/Xaml/CreateValuesVisitor.cs @@ -43,7 +43,7 @@ public void Visit(ElementNode node, INode parentNode) { object value = null; - var type = XamlParser.GetElementType(node.XmlType, node, Context.RootElement?.GetType().Assembly, + var type = XamlParser.GetElementType(node.XmlType, true, node, Context.RootElement?.GetType().Assembly, out XamlParseException xpe); if (xpe != null) { diff --git a/src/Controls/src/Xaml/MarkupExtensions/StaticExtension.cs b/src/Controls/src/Xaml/MarkupExtensions/StaticExtension.cs index 2c8101430eb8..cfddb577b92a 100644 --- a/src/Controls/src/Xaml/MarkupExtensions/StaticExtension.cs +++ b/src/Controls/src/Xaml/MarkupExtensions/StaticExtension.cs @@ -24,7 +24,7 @@ public object ProvideValue(IServiceProvider serviceProvider) var typename = Member.Substring(0, dotIdx); var membername = Member.Substring(dotIdx + 1); - var type = typeResolver.Resolve(typename, serviceProvider); + var type = typeResolver.Resolve(typename, tryExtensionFirst: false, serviceProvider: serviceProvider); var pinfo = type.GetRuntimeProperties().FirstOrDefault(pi => pi.Name == membername && pi.GetMethod.IsStatic); if (pinfo != null) diff --git a/src/Controls/src/Xaml/MarkupExtensions/TypeExtension.cs b/src/Controls/src/Xaml/MarkupExtensions/TypeExtension.cs index 1bdde80cb3a2..2466676d9848 100644 --- a/src/Controls/src/Xaml/MarkupExtensions/TypeExtension.cs +++ b/src/Controls/src/Xaml/MarkupExtensions/TypeExtension.cs @@ -20,7 +20,7 @@ public Type ProvideValue(IServiceProvider serviceProvider) throw new XamlParseException("TypeName isn't set.", li); } - return typeResolver.Resolve(TypeName, serviceProvider); + return typeResolver.Resolve(TypeName, tryExtensionFirst: false, serviceProvider: serviceProvider); } object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider) diff --git a/src/Controls/src/Xaml/XamlParser.cs b/src/Controls/src/Xaml/XamlParser.cs index f5a7b1f3c1fa..f2d2c3bc5d68 100644 --- a/src/Controls/src/Xaml/XamlParser.cs +++ b/src/Controls/src/Xaml/XamlParser.cs @@ -356,7 +356,7 @@ static void GatherXmlnsDefinitionAttributes() } } - public static Type GetElementType(XmlType xmlType, IXmlLineInfo xmlInfo, Assembly currentAssembly, + public static Type GetElementType(XmlType xmlType, bool tryExtensionFirst, IXmlLineInfo xmlInfo, Assembly currentAssembly, out XamlParseException exception) { bool hasRetriedNsSearch = false; @@ -374,7 +374,7 @@ public static Type GetElementType(XmlType xmlType, IXmlLineInfo xmlInfo, Assembl if (t is not null && t.IsPublicOrVisibleInternal(currentAssembly)) return t; return null; - }); + }, tryExtensionFirst); var typeArguments = xmlType.TypeArguments; exception = null; @@ -398,7 +398,7 @@ public static Type GetElementType(XmlType xmlType, IXmlLineInfo xmlInfo, Assembl XamlParseException innerexception = null; var args = typeArguments.Select(delegate (XmlType xmltype) { - var t = GetElementType(xmltype, xmlInfo, currentAssembly, out XamlParseException xpe); + var t = GetElementType(xmltype, true, xmlInfo, currentAssembly, out XamlParseException xpe); if (xpe != null) { innerexception = xpe; diff --git a/src/Controls/src/Xaml/XamlServiceProvider.cs b/src/Controls/src/Xaml/XamlServiceProvider.cs index 23bf38738b32..d3c9ad3f2484 100644 --- a/src/Controls/src/Xaml/XamlServiceProvider.cs +++ b/src/Controls/src/Xaml/XamlServiceProvider.cs @@ -177,8 +177,11 @@ internal XamlTypeResolver(IXmlNamespaceResolver namespaceResolver, GetTypeFromXm } Type IXamlTypeResolver.Resolve(string qualifiedTypeName, IServiceProvider serviceProvider) + => ((IXamlTypeResolver)this).Resolve(qualifiedTypeName, true, serviceProvider); + + Type IXamlTypeResolver.Resolve(string qualifiedTypeName, bool tryExtensionFirst, IServiceProvider serviceProvider) { - var type = Resolve(qualifiedTypeName, serviceProvider, out XamlParseException e); + var type = Resolve(qualifiedTypeName, tryExtensionFirst, serviceProvider, out XamlParseException e); if (e != null) throw e; return type; @@ -186,18 +189,18 @@ Type IXamlTypeResolver.Resolve(string qualifiedTypeName, IServiceProvider servic bool IXamlTypeResolver.TryResolve(string qualifiedTypeName, out Type type) { - type = Resolve(qualifiedTypeName, null, out XamlParseException exception); + type = Resolve(qualifiedTypeName, true, null, out XamlParseException exception); return exception == null; } internal bool TryResolve(XmlType xmlType, out Type type) { XamlParseException exception; - type = getTypeFromXmlName(xmlType, null, currentAssembly, out exception); + type = getTypeFromXmlName(xmlType, true, null, currentAssembly, out exception); return exception == null; } - Type Resolve(string qualifiedTypeName, IServiceProvider serviceProvider, out XamlParseException exception) + Type Resolve(string qualifiedTypeName, bool tryExtensionFirst, IServiceProvider serviceProvider, out XamlParseException exception) { exception = null; var split = qualifiedTypeName.Split(':'); @@ -230,10 +233,10 @@ Type Resolve(string qualifiedTypeName, IServiceProvider serviceProvider, out Xam return null; } - return getTypeFromXmlName(new XmlType(namespaceuri, name, null), xmlLineInfo, currentAssembly, out exception); + return getTypeFromXmlName(new XmlType(namespaceuri, name, null), tryExtensionFirst, xmlLineInfo, currentAssembly, out exception); } - internal delegate Type GetTypeFromXmlName(XmlType xmlType, IXmlLineInfo xmlInfo, Assembly currentAssembly, out XamlParseException exception); + internal delegate Type GetTypeFromXmlName(XmlType xmlType, bool tryExtensionFirst, IXmlLineInfo xmlInfo, Assembly currentAssembly, out XamlParseException exception); } class XamlRootObjectProvider : IRootObjectProvider diff --git a/src/Controls/src/Xaml/XmlTypeXamlExtensions.cs b/src/Controls/src/Xaml/XmlTypeXamlExtensions.cs index 95720dc64325..10039ed0a2c4 100644 --- a/src/Controls/src/Xaml/XmlTypeXamlExtensions.cs +++ b/src/Controls/src/Xaml/XmlTypeXamlExtensions.cs @@ -37,7 +37,8 @@ static class XmlTypeXamlExtensions this XmlType xmlType, IEnumerable xmlnsDefinitions, string defaultAssemblyName, - Func<(string typeName, string clrNamespace, string assemblyName), T> refFromTypeInfo) + Func<(string typeName, string clrNamespace, string assemblyName), T> refFromTypeInfo, + bool tryExtensionFirst = true) where T : class { var lookupAssemblies = new List(); @@ -61,7 +62,7 @@ static class XmlTypeXamlExtensions } var lookupNames = new List(); - if (elementName != "DataTemplate" && !elementName.EndsWith("Extension", StringComparison.Ordinal)) + if (elementName != "DataTemplate" && !elementName.EndsWith("Extension", StringComparison.Ordinal) && tryExtensionFirst) lookupNames.Add(elementName + "Extension"); lookupNames.Add(elementName); diff --git a/src/Controls/tests/Xaml.UnitTests/Issues/Maui11833.xaml b/src/Controls/tests/Xaml.UnitTests/Issues/Maui11833.xaml new file mode 100644 index 000000000000..d522d9925b6a --- /dev/null +++ b/src/Controls/tests/Xaml.UnitTests/Issues/Maui11833.xaml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/Xaml.UnitTests/Issues/Maui11833.xaml.cs b/src/Controls/tests/Xaml.UnitTests/Issues/Maui11833.xaml.cs new file mode 100644 index 000000000000..36016ceb9ac5 --- /dev/null +++ b/src/Controls/tests/Xaml.UnitTests/Issues/Maui11833.xaml.cs @@ -0,0 +1,25 @@ +using Microsoft.Maui.Controls.Core.UnitTests; +using NUnit.Framework; + +namespace Microsoft.Maui.Controls.Xaml.UnitTests +{ + public partial class Maui11833 : ContentPage + { + public Maui11833() => InitializeComponent(); + public Maui11833(bool useCompiledXaml) + { + //this stub will be replaced at compile time + } + + [TestFixture] + class Tests + { + [Test] + public void xStaticBinding([Values(false, true)] bool useCompiledXaml) + { + var page = new Maui11833(useCompiledXaml); + } + } + } + +} \ No newline at end of file diff --git a/src/Controls/tests/Xaml.UnitTests/LoaderTests.cs b/src/Controls/tests/Xaml.UnitTests/LoaderTests.cs index 4ad6d3d0376f..0373e50091e5 100644 --- a/src/Controls/tests/Xaml.UnitTests/LoaderTests.cs +++ b/src/Controls/tests/Xaml.UnitTests/LoaderTests.cs @@ -792,7 +792,7 @@ public void StyleWithoutTargetTypeThrows() public void BindingIsResolvedAsBindingExtension() // https://github.com/xamarin/Microsoft.Maui.Controls/issues/3606#issuecomment-422377338 { - var bindingType = XamlParser.GetElementType(new XmlType("http://schemas.microsoft.com/dotnet/2021/maui", "Binding", null), null, null, out var ex); + var bindingType = XamlParser.GetElementType(new XmlType("http://schemas.microsoft.com/dotnet/2021/maui", "Binding", null), true, null, null, out var ex); Assert.That(ex, Is.Null); Assert.That(bindingType, Is.EqualTo(typeof(BindingExtension))); var module = ModuleDefinition.CreateModule("foo", new ModuleParameters() diff --git a/src/Controls/tests/Xaml.UnitTests/TypeExtensionTests.cs b/src/Controls/tests/Xaml.UnitTests/TypeExtensionTests.cs index 7177d199fde5..28674f086e22 100644 --- a/src/Controls/tests/Xaml.UnitTests/TypeExtensionTests.cs +++ b/src/Controls/tests/Xaml.UnitTests/TypeExtensionTests.cs @@ -51,5 +51,12 @@ public void TestWithExplicitTypeName() var markupString = @"{x:Type TypeName=sys:String}"; Assert.AreEqual(typeof(string), (new MarkupExtensionParser()).ParseExpression(ref markupString, serviceProvider)); } + + [Test] + public void DontExpandToExtension() + { + var markupString = @"{x:Type Binding}"; + Assert.AreEqual(typeof(Binding), (new MarkupExtensionParser()).ParseExpression(ref markupString, serviceProvider)); + } } } \ No newline at end of file