diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Given_HotReloadEnabledInBuild.cs b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Given_HotReloadEnabledInBuild.cs index 8694075a0a51..a8519c1b422c 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Given_HotReloadEnabledInBuild.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Given_HotReloadEnabledInBuild.cs @@ -332,4 +332,61 @@ public MainPage() await test.RunAsync(); } + + [TestMethod] + public async Task SetOriginalSourceLocationIncludedInOutputForEmptyDataTemplates() + { + var xamlFile = new XamlFile("EmptyDataTemplatePage.xaml", + """ + + + + + + + + + + + + """); + var configOverride = new Dictionary { { "build_property.UnoForceHotReloadCodeGen", "true" } }; + var test = new Verify.Test(xamlFile) + { + TestState = + { + Sources = + { + """ + using Microsoft.UI.Xaml; + using Microsoft.UI.Xaml.Controls; + namespace TestRepro + { + public sealed partial class EmptyDataTemplatePage : Page + { + public EmptyDataTemplatePage() + { + this.InitializeComponent(); + } + } + } + """ + } + }, + ReferenceAssemblies = _Dotnet.Current.WithUnoPackage(), + GlobalConfigOverride = configOverride, + }.AddGeneratedSources(); + + await test.RunAsync(); + } } diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706.cs b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706.cs new file mode 100644 index 000000000000..98e8134c5d82 --- /dev/null +++ b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706.cs @@ -0,0 +1,240 @@ +// +#pragma warning disable CS0114 +#pragma warning disable CS0108 +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Uno.UI; +using Uno.UI.Xaml; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +using Microsoft.UI.Xaml.Data; +using Microsoft.UI.Xaml.Documents; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Media.Animation; +using Microsoft.UI.Xaml.Shapes; +using Windows.UI.Text; +using Uno.Extensions; +using Uno; +using Uno.UI.Helpers; +using Uno.UI.Helpers.Xaml; +using MyProject; + +#if __ANDROID__ +using _View = Android.Views.View; +#elif __IOS__ +using _View = UIKit.UIView; +#elif __MACOS__ +using _View = AppKit.NSView; +#else +using _View = Microsoft.UI.Xaml.UIElement; +#endif + +namespace TestRepro +{ + partial class EmptyDataTemplatePage : global::Microsoft.UI.Xaml.Controls.Page + { + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + private const string __baseUri_prefix_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706 = "ms-appx:///TestProject/"; + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + private const string __baseUri_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706 = "ms-appx:///TestProject/"; + private global::Microsoft.UI.Xaml.NameScope __nameScope = new global::Microsoft.UI.Xaml.NameScope(); + private void InitializeComponent() + { + NameScope.SetNameScope(this, __nameScope); + var __that = this; + base.IsParsing = true; + Resources[ + "MyEmptyTemplate" + ] = + new global::Uno.UI.Xaml.WeakResourceInitializer(this, __ResourceOwner_1 => + { + return + new global::Microsoft.UI.Xaml.DataTemplate( ) .GenericApply(__that, __nameScope, (ApplyMethod_0 )) + ; + } + ) + ; + // Source 0\EmptyDataTemplatePage.xaml (Line 1:3) + base.Content = + new global::Microsoft.UI.Xaml.Controls.StackPanel + { + IsParsing = true, + // Source 0\EmptyDataTemplatePage.xaml (Line 11:3) + Children = + { + new global::Microsoft.UI.Xaml.Controls.ListView + { + IsParsing = true, + // Source 0\EmptyDataTemplatePage.xaml (Line 12:4) + } + .GenericApply(__that, __nameScope, (ApplyMethod_1 )) + , + new global::Microsoft.UI.Xaml.Controls.Button + { + IsParsing = true, + Name = "ButtonWithEmptyDataTemplate", + ContentTemplate = new global::Microsoft.UI.Xaml.DataTemplate( ) .GenericApply(__that, __nameScope, (ApplyMethod_2 )) + , + // Source 0\EmptyDataTemplatePage.xaml (Line 13:4) + } + .GenericApply(__that, __nameScope, (ApplyMethod_3 )) + , + } + } + .GenericApply(__that, __nameScope, (ApplyMethod_4 )) + ; + + this + .GenericApply(__that, __nameScope, (ApplyMethod_5 )) + .GenericApply(__that, __nameScope, (ApplyMethod_6 )) + ; + OnInitializeCompleted(); + + Bindings = new EmptyDataTemplatePage_Bindings(this); + ((global::Microsoft.UI.Xaml.FrameworkElement)this).Loading += __UpdateBindingsAndResources; + } + partial void OnInitializeCompleted(); + private void __UpdateBindingsAndResources(global::Microsoft.UI.Xaml.FrameworkElement s, object e) + { + this.Bindings.UpdateResources(); + } + private void ApplyMethod_0(global::System.Object __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope) + { + global::Uno.UI.Helpers.MarkupHelper.SetElementProperty(__p1, "OriginalSourceLocation", "file:///C:/Project/0/EmptyDataTemplatePage.xaml#L7:4"); + } + + private void ApplyMethod_1(global::Microsoft.UI.Xaml.Controls.ListView __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope) + { + /* _isTopLevelDictionary:False */ + __that._component_0 = __p1; + global::Uno.UI.ResourceResolverSingleton.Instance.ApplyResource(__p1, global::Microsoft.UI.Xaml.Controls.ListView.ItemTemplateProperty, "MyItemTemplate", isThemeResourceExtension: false, isHotReloadSupported: true, context: global::MyProject.GlobalStaticResources.__ParseContext_); + global::Uno.UI.FrameworkElementHelper.SetBaseUri(__p1, __baseUri_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706, "file:///C:/Project/0/EmptyDataTemplatePage.xaml", 12, 4); + __p1.CreationComplete(); + } + + private void ApplyMethod_2(global::System.Object __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope) + { + global::Uno.UI.Helpers.MarkupHelper.SetElementProperty(__p1, "OriginalSourceLocation", "file:///C:/Project/0/EmptyDataTemplatePage.xaml#L15:6"); + } + + private void ApplyMethod_3(global::Microsoft.UI.Xaml.Controls.Button __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope) + { + __nameScope.RegisterName("ButtonWithEmptyDataTemplate", __p1); + __that.ButtonWithEmptyDataTemplate = __p1; + global::Uno.UI.FrameworkElementHelper.SetBaseUri(__p1, __baseUri_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706, "file:///C:/Project/0/EmptyDataTemplatePage.xaml", 13, 4); + __p1.CreationComplete(); + } + + private void ApplyMethod_4(global::Microsoft.UI.Xaml.Controls.StackPanel __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope) + { + global::Uno.UI.FrameworkElementHelper.SetBaseUri(__p1, __baseUri_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706, "file:///C:/Project/0/EmptyDataTemplatePage.xaml", 11, 3); + __p1.CreationComplete(); + } + + private void ApplyMethod_5(global::Microsoft.UI.Xaml.Controls.Page __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope) + { + // Source 0\EmptyDataTemplatePage.xaml (Line 1:3) + + // WARNING Property __p1.base does not exist on {http://schemas.microsoft.com/winfx/2006/xaml/presentation}Page, the namespace is http://www.w3.org/XML/1998/namespace. This error was considered irrelevant by the XamlFileGenerator + } + + private void ApplyMethod_6(global::Microsoft.UI.Xaml.Controls.Page __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope) + { + /* _isTopLevelDictionary:False */ + __that._component_1 = __p1; + // Class TestRepro.EmptyDataTemplatePage + global::Uno.UI.ResourceResolverSingleton.Instance.ApplyResource(__p1, global::Microsoft.UI.Xaml.Controls.Page.BackgroundProperty, "ApplicationPageBackgroundThemeBrush", isThemeResourceExtension: true, isHotReloadSupported: true, context: global::MyProject.GlobalStaticResources.__ParseContext_); + global::Uno.UI.FrameworkElementHelper.SetBaseUri(__p1, __baseUri_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706, "file:///C:/Project/0/EmptyDataTemplatePage.xaml", 1, 3); + __p1.CreationComplete(); + } + + private global::Microsoft.UI.Xaml.Data.ElementNameSubject _ButtonWithEmptyDataTemplateSubject { get; set; } = new global::Microsoft.UI.Xaml.Data.ElementNameSubject(); + private global::Microsoft.UI.Xaml.Controls.Button ButtonWithEmptyDataTemplate + { + get + { + return (global::Microsoft.UI.Xaml.Controls.Button)_ButtonWithEmptyDataTemplateSubject.ElementInstance; + } + set + { + _ButtonWithEmptyDataTemplateSubject.ElementInstance = value; + } + } + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + [global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdate] + private class __EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706_TestReproEmptyDataTemplatePage + { + } + private global::Microsoft.UI.Xaml.Markup.ComponentHolder _component_0_Holder { get; } = new global::Microsoft.UI.Xaml.Markup.ComponentHolder(isWeak: true); + private global::Microsoft.UI.Xaml.Controls.ListView _component_0 + { + get + { + return (global::Microsoft.UI.Xaml.Controls.ListView)_component_0_Holder.Instance; + } + set + { + _component_0_Holder.Instance = value; + } + } + private global::Microsoft.UI.Xaml.Markup.ComponentHolder _component_1_Holder { get; } = new global::Microsoft.UI.Xaml.Markup.ComponentHolder(isWeak: true); + private global::Microsoft.UI.Xaml.Controls.Page _component_1 + { + get + { + return (global::Microsoft.UI.Xaml.Controls.Page)_component_1_Holder.Instance; + } + set + { + _component_1_Holder.Instance = value; + } + } + private interface IEmptyDataTemplatePage_Bindings + { + void Initialize(); + void Update(); + void UpdateResources(); + void StopTracking(); + void NotifyXLoad(string name); + } + #pragma warning disable 0169 // Suppress unused field warning in case Bindings is not used. + private IEmptyDataTemplatePage_Bindings Bindings; + #pragma warning restore 0169 + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + private class EmptyDataTemplatePage_Bindings : IEmptyDataTemplatePage_Bindings + { + #if UNO_HAS_UIELEMENT_IMPLICIT_PINNING + private global::System.WeakReference _ownerReference; + private global::TestRepro.EmptyDataTemplatePage Owner { get => (global::TestRepro.EmptyDataTemplatePage)_ownerReference?.Target; set => _ownerReference = new global::System.WeakReference(value); } + #else + private global::TestRepro.EmptyDataTemplatePage Owner { get; set; } + #endif + public EmptyDataTemplatePage_Bindings(global::TestRepro.EmptyDataTemplatePage owner) + { + Owner = owner; + } + void IEmptyDataTemplatePage_Bindings.NotifyXLoad(string name) + { + } + void IEmptyDataTemplatePage_Bindings.Initialize() + { + } + void IEmptyDataTemplatePage_Bindings.Update() + { + var owner = Owner; + } + void IEmptyDataTemplatePage_Bindings.UpdateResources() + { + var owner = Owner; + owner._component_0.UpdateResourceBindings(); + owner._component_1.UpdateResourceBindings(); + } + void IEmptyDataTemplatePage_Bindings.StopTracking() + { + } + } + } +} diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_GlobalStaticResources.cs b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_GlobalStaticResources.cs new file mode 100644 index 000000000000..d4de7cabbd66 --- /dev/null +++ b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_GlobalStaticResources.cs @@ -0,0 +1,59 @@ +// +namespace MyProject +{ + /// + /// Contains all the static resources defined for the application + /// + [global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdate] + public sealed partial class GlobalStaticResources + { + static bool _initialized; + private static bool _stylesRegistered; + private static bool _dictionariesRegistered; + internal static global::Uno.UI.Xaml.XamlParseContext __ParseContext_ { get; } = new global::Uno.UI.Xaml.XamlParseContext() + { + AssemblyName = "TestProject", + } + ; + + static GlobalStaticResources() + { + Initialize(); + } + public static void Initialize() + { + if (!_initialized) + { + _initialized = true; + global::Uno.UI.Toolkit.GlobalStaticResources.Initialize(); + global::Uno.UI.GlobalStaticResources.Initialize(); + global::Uno.UI.Toolkit.GlobalStaticResources.RegisterDefaultStyles(); + global::Uno.UI.GlobalStaticResources.RegisterDefaultStyles(); + global::Uno.UI.Toolkit.GlobalStaticResources.RegisterResourceDictionariesBySource(); + global::Uno.UI.GlobalStaticResources.RegisterResourceDictionariesBySource(); + } + } + public static void RegisterDefaultStyles() + { + if(!_stylesRegistered) + { + _stylesRegistered = true; + RegisterDefaultStyles_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706(); + } + } + // Register ResourceDictionaries using ms-appx:/// syntax, this is called for external resources + public static void RegisterResourceDictionariesBySource() + { + if(!_dictionariesRegistered) + { + _dictionariesRegistered = true; + } + } + // Register ResourceDictionaries using ms-resource:/// syntax, this is called for local resources + internal static void RegisterResourceDictionariesBySourceLocal() + { + } + static partial void RegisterDefaultStyles_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706(); + + } +} diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_LocalizationResources.cs b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_LocalizationResources.cs new file mode 100644 index 000000000000..115ce87c0105 --- /dev/null +++ b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_LocalizationResources.cs @@ -0,0 +1,2 @@ +// +[assembly: global::System.Reflection.AssemblyMetadata("UnoHasLocalizationResources", "False")] \ No newline at end of file diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Verifiers/CSGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Verifiers/CSGenerator.cs index 383632841446..79fe7ee82300 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Verifiers/CSGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Verifiers/CSGenerator.cs @@ -1,8 +1,6 @@ -#if DEBUG -// Uncomment the following line to write expected files to disk +// Uncomment the following line to write expected files to disk // Don't commit this line uncommented. // #define WRITE_EXPECTED -#endif using System.Collections.Immutable; using System.Diagnostics; @@ -16,6 +14,11 @@ using Uno.UI.SourceGenerators.MetadataUpdates; using Uno.UI.SourceGenerators.XamlGenerator; +#if !DEBUG && WRITE_EXPECTED +#error Cannot commit with #define WRITE_EXPECTED +#endif + + namespace Uno.UI.SourceGenerators.Tests.Verifiers { public record struct XamlFile(string FileName, string Contents); diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs index 924580d3323b..33f957f64a72 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs @@ -5996,28 +5996,28 @@ private void BuildChild(IIndentedStringBuilder writer, XamlMemberDefinition? own var contentOwner = xamlObjectDefinition.Members.FirstOrDefault(m => m.Member.Name == "_UnknownContent"); var contentLocation = (IXamlLocation)xamlObjectDefinition.Members.FirstOrDefault(m => m.Member.Name == "Key") ?? xamlObjectDefinition; - if (contentOwner != null) + if (contentOwner is not null || _isHotReloadEnabled) // If Hot Reload is enabled, we still need to attach the source location, even on empty elements { - var resourceOwner = CurrentResourceOwnerName; - + if (contentOwner is not null) + { + var resourceOwner = CurrentResourceOwnerName; #if USE_NEW_TP_CODEGEN - writer.Append($"{resourceOwner}, (__owner, __settings) => "); + writer.Append($"{resourceOwner}, (__owner, __settings) => "); #else - writer.Append($"{resourceOwner}, (__owner) => "); + writer.Append($"{resourceOwner}, (__owner) => "); #endif - - // This case is to support the layout switching for the ListViewBaseLayout, which is not - // a FrameworkTemplate. This will need to be removed when this custom list view is removed. - var returnType = typeName == "ListViewBaseLayoutTemplate" ? "global::Uno.UI.Controls.Legacy.ListViewBaseLayout" : "_View"; - BuildChildThroughSubclass(writer, contentOwner, returnType); + // This case is to support the layout switching for the ListViewBaseLayout, which is not + // a FrameworkTemplate. This will need to be removed when this custom list view is removed. + var returnType = typeName == "ListViewBaseLayoutTemplate" ? "global::Uno.UI.Controls.Legacy.ListViewBaseLayout" : "_View"; + BuildChildThroughSubclass(writer, contentOwner, returnType); + } writer.AppendIndented(")"); + if (_isHotReloadEnabled) { - using (var applyWriter = CreateApplyBlock(writer, null, out var closureName)) - { - TrySetOriginalSourceLocation(applyWriter, closureName, contentLocation.LineNumber, contentLocation.LinePosition); - } + using var applyWriter = CreateApplyBlock(writer, null, out var closureName); + TrySetOriginalSourceLocation(applyWriter, closureName, contentLocation.LineNumber, contentLocation.LinePosition); } }