From 6e621e553a5b08921dbd42fc3f84b016c8c8dc5a Mon Sep 17 00:00:00 2001 From: "Artyom V. Gorchakov" Date: Sun, 21 Feb 2021 15:13:07 +0300 Subject: [PATCH] feature: Generate this.AttachDevTools() if Avalonia.Diagnostics is nearby (#35) --- .../Avalonia.NameGenerator.Tests.csproj | 4 +- .../GeneratedDevTools/AttachedProps.txt | 26 ++++++++++ .../GeneratedDevTools/CustomControls.txt | 30 +++++++++++ .../GeneratedDevTools/DataTemplates.txt | 28 ++++++++++ .../GeneratedDevTools/DevToolsCode.cs | 34 +++++++++++++ .../GeneratedDevTools/FieldModifier.txt | 36 +++++++++++++ .../GeneratedDevTools/NamedControl.txt | 26 ++++++++++ .../GeneratedDevTools/NamedControls.txt | 30 +++++++++++ .../GeneratedDevTools/NoNamedControls.txt | 26 ++++++++++ .../GeneratedDevTools/SignUpView.txt | 42 +++++++++++++++ .../GeneratedDevTools/xNamedControl.txt | 26 ++++++++++ .../GeneratedDevTools/xNamedControls.txt | 30 +++++++++++ .../AttachedProps.txt | 0 .../CustomControls.txt | 0 .../DataTemplates.txt | 0 .../FieldModifier.txt | 0 .../InitializeComponentCode.cs | 6 ++- .../NamedControl.txt | 0 .../NamedControls.txt | 0 .../NoNamedControls.txt | 0 .../SignUpView.txt | 0 .../xNamedControl.txt | 0 .../xNamedControls.txt | 0 .../InitializeComponentTests.cs | 51 +++++++++++++------ .../Views/View.cs | 6 ++- .../Compiler/RoslynTypeSystem.cs | 37 +++++--------- .../Domain/INameGenerator.cs | 12 +---- .../Domain/INameResolver.cs | 14 +---- .../Domain/IViewResolver.cs | 14 +---- .../Domain/IsExternalInit.cs | 5 ++ ...niaNameSourceGenerator.cs => Generator.cs} | 4 +- .../InitializeComponentCodeGenerator.cs | 27 +++++++--- src/Directory.Build.props | 1 + 33 files changed, 424 insertions(+), 91 deletions(-) create mode 100644 src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/AttachedProps.txt create mode 100644 src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/CustomControls.txt create mode 100644 src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/DataTemplates.txt create mode 100644 src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/DevToolsCode.cs create mode 100644 src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/FieldModifier.txt create mode 100644 src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/NamedControl.txt create mode 100644 src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/NamedControls.txt create mode 100644 src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/NoNamedControls.txt create mode 100644 src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/SignUpView.txt create mode 100644 src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/xNamedControl.txt create mode 100644 src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/xNamedControls.txt rename src/Avalonia.NameGenerator.Tests/InitializeComponent/{GeneratedCode => GeneratedInitializeComponent}/AttachedProps.txt (100%) rename src/Avalonia.NameGenerator.Tests/InitializeComponent/{GeneratedCode => GeneratedInitializeComponent}/CustomControls.txt (100%) rename src/Avalonia.NameGenerator.Tests/InitializeComponent/{GeneratedCode => GeneratedInitializeComponent}/DataTemplates.txt (100%) rename src/Avalonia.NameGenerator.Tests/InitializeComponent/{GeneratedCode => GeneratedInitializeComponent}/FieldModifier.txt (100%) rename src/Avalonia.NameGenerator.Tests/InitializeComponent/{GeneratedCode => GeneratedInitializeComponent}/InitializeComponentCode.cs (88%) rename src/Avalonia.NameGenerator.Tests/InitializeComponent/{GeneratedCode => GeneratedInitializeComponent}/NamedControl.txt (100%) rename src/Avalonia.NameGenerator.Tests/InitializeComponent/{GeneratedCode => GeneratedInitializeComponent}/NamedControls.txt (100%) rename src/Avalonia.NameGenerator.Tests/InitializeComponent/{GeneratedCode => GeneratedInitializeComponent}/NoNamedControls.txt (100%) rename src/Avalonia.NameGenerator.Tests/InitializeComponent/{GeneratedCode => GeneratedInitializeComponent}/SignUpView.txt (100%) rename src/Avalonia.NameGenerator.Tests/InitializeComponent/{GeneratedCode => GeneratedInitializeComponent}/xNamedControl.txt (100%) rename src/Avalonia.NameGenerator.Tests/InitializeComponent/{GeneratedCode => GeneratedInitializeComponent}/xNamedControls.txt (100%) create mode 100644 src/Avalonia.NameGenerator/Domain/IsExternalInit.cs rename src/Avalonia.NameGenerator/{AvaloniaNameSourceGenerator.cs => Generator.cs} (99%) diff --git a/src/Avalonia.NameGenerator.Tests/Avalonia.NameGenerator.Tests.csproj b/src/Avalonia.NameGenerator.Tests/Avalonia.NameGenerator.Tests.csproj index 8ddbd84ccc..a214438016 100644 --- a/src/Avalonia.NameGenerator.Tests/Avalonia.NameGenerator.Tests.csproj +++ b/src/Avalonia.NameGenerator.Tests/Avalonia.NameGenerator.Tests.csproj @@ -8,6 +8,7 @@ + @@ -17,7 +18,8 @@ - + + diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/AttachedProps.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/AttachedProps.txt new file mode 100644 index 0000000000..bcfcd11625 --- /dev/null +++ b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/AttachedProps.txt @@ -0,0 +1,26 @@ +// + +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Sample.App +{ + partial class SampleView + { + internal global::Avalonia.Controls.TextBox UserNameTextBox { get; set; } + + public void InitializeComponent(bool loadXaml = true) + { + if (loadXaml) + { + AvaloniaXamlLoader.Load(this); + } + +#if DEBUG + this.AttachDevTools(); +#endif + + UserNameTextBox = this.FindControl("UserNameTextBox"); + } + } +} diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/CustomControls.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/CustomControls.txt new file mode 100644 index 0000000000..f44bef9f6b --- /dev/null +++ b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/CustomControls.txt @@ -0,0 +1,30 @@ +// + +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Sample.App +{ + partial class SampleView + { + internal global::Avalonia.ReactiveUI.RoutedViewHost ClrNamespaceRoutedViewHost { get; set; } + internal global::Avalonia.ReactiveUI.RoutedViewHost UriRoutedViewHost { get; set; } + internal global::Controls.CustomTextBox UserNameTextBox { get; set; } + + public void InitializeComponent(bool loadXaml = true) + { + if (loadXaml) + { + AvaloniaXamlLoader.Load(this); + } + +#if DEBUG + this.AttachDevTools(); +#endif + + ClrNamespaceRoutedViewHost = this.FindControl("ClrNamespaceRoutedViewHost"); + UriRoutedViewHost = this.FindControl("UriRoutedViewHost"); + UserNameTextBox = this.FindControl("UserNameTextBox"); + } + } +} diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/DataTemplates.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/DataTemplates.txt new file mode 100644 index 0000000000..3355e8f6d7 --- /dev/null +++ b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/DataTemplates.txt @@ -0,0 +1,28 @@ +// + +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Sample.App +{ + partial class SampleView + { + internal global::Avalonia.Controls.TextBox UserNameTextBox { get; set; } + internal global::Avalonia.Controls.ListBox NamedListBox { get; set; } + + public void InitializeComponent(bool loadXaml = true) + { + if (loadXaml) + { + AvaloniaXamlLoader.Load(this); + } + +#if DEBUG + this.AttachDevTools(); +#endif + + UserNameTextBox = this.FindControl("UserNameTextBox"); + NamedListBox = this.FindControl("NamedListBox"); + } + } +} diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/DevToolsCode.cs b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/DevToolsCode.cs new file mode 100644 index 0000000000..9b8e6959c1 --- /dev/null +++ b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/DevToolsCode.cs @@ -0,0 +1,34 @@ +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace Avalonia.NameGenerator.Tests.InitializeComponent.GeneratedDevTools +{ + public static class DevToolsCode + { + public const string NamedControl = "NamedControl.txt"; + public const string NamedControls = "NamedControls.txt"; + public const string XNamedControl = "xNamedControl.txt"; + public const string XNamedControls = "xNamedControls.txt"; + public const string NoNamedControls = "NoNamedControls.txt"; + public const string CustomControls = "CustomControls.txt"; + public const string DataTemplates = "DataTemplates.txt"; + public const string SignUpView = "SignUpView.txt"; + public const string AttachedProps = "AttachedProps.txt"; + public const string FieldModifier = "FieldModifier.txt"; + + public static async Task Load(string generatedCodeResourceName) + { + var assembly = typeof(XamlXNameResolverTests).Assembly; + var fullResourceName = assembly + .GetManifestResourceNames() + .First(name => name.Contains("InitializeComponent") && + name.Contains("GeneratedDevTools") && + name.EndsWith(generatedCodeResourceName)); + + await using var stream = assembly.GetManifestResourceStream(fullResourceName); + using var reader = new StreamReader(stream!); + return await reader.ReadToEndAsync(); + } + } +} \ No newline at end of file diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/FieldModifier.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/FieldModifier.txt new file mode 100644 index 0000000000..239a556fd8 --- /dev/null +++ b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/FieldModifier.txt @@ -0,0 +1,36 @@ +// + +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Sample.App +{ + partial class SampleView + { + public global::Avalonia.Controls.TextBox FirstNameTextBox { get; set; } + public global::Avalonia.Controls.TextBox LastNameTextBox { get; set; } + protected global::Avalonia.Controls.TextBox PasswordTextBox { get; set; } + private global::Avalonia.Controls.TextBox ConfirmPasswordTextBox { get; set; } + internal global::Avalonia.Controls.Button SignUpButton { get; set; } + internal global::Avalonia.Controls.Button RegisterButton { get; set; } + + public void InitializeComponent(bool loadXaml = true) + { + if (loadXaml) + { + AvaloniaXamlLoader.Load(this); + } + +#if DEBUG + this.AttachDevTools(); +#endif + + FirstNameTextBox = this.FindControl("FirstNameTextBox"); + LastNameTextBox = this.FindControl("LastNameTextBox"); + PasswordTextBox = this.FindControl("PasswordTextBox"); + ConfirmPasswordTextBox = this.FindControl("ConfirmPasswordTextBox"); + SignUpButton = this.FindControl("SignUpButton"); + RegisterButton = this.FindControl("RegisterButton"); + } + } +} diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/NamedControl.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/NamedControl.txt new file mode 100644 index 0000000000..bcfcd11625 --- /dev/null +++ b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/NamedControl.txt @@ -0,0 +1,26 @@ +// + +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Sample.App +{ + partial class SampleView + { + internal global::Avalonia.Controls.TextBox UserNameTextBox { get; set; } + + public void InitializeComponent(bool loadXaml = true) + { + if (loadXaml) + { + AvaloniaXamlLoader.Load(this); + } + +#if DEBUG + this.AttachDevTools(); +#endif + + UserNameTextBox = this.FindControl("UserNameTextBox"); + } + } +} diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/NamedControls.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/NamedControls.txt new file mode 100644 index 0000000000..a731f1d04a --- /dev/null +++ b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/NamedControls.txt @@ -0,0 +1,30 @@ +// + +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Sample.App +{ + partial class SampleView + { + internal global::Avalonia.Controls.TextBox UserNameTextBox { get; set; } + internal global::Avalonia.Controls.TextBox PasswordTextBox { get; set; } + internal global::Avalonia.Controls.Button SignUpButton { get; set; } + + public void InitializeComponent(bool loadXaml = true) + { + if (loadXaml) + { + AvaloniaXamlLoader.Load(this); + } + +#if DEBUG + this.AttachDevTools(); +#endif + + UserNameTextBox = this.FindControl("UserNameTextBox"); + PasswordTextBox = this.FindControl("PasswordTextBox"); + SignUpButton = this.FindControl("SignUpButton"); + } + } +} diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/NoNamedControls.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/NoNamedControls.txt new file mode 100644 index 0000000000..ef0349d2b0 --- /dev/null +++ b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/NoNamedControls.txt @@ -0,0 +1,26 @@ +// + +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Sample.App +{ + partial class SampleView + { + + + public void InitializeComponent(bool loadXaml = true) + { + if (loadXaml) + { + AvaloniaXamlLoader.Load(this); + } + +#if DEBUG + this.AttachDevTools(); +#endif + + + } + } +} diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/SignUpView.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/SignUpView.txt new file mode 100644 index 0000000000..23bc5e8c2a --- /dev/null +++ b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/SignUpView.txt @@ -0,0 +1,42 @@ +// + +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Sample.App +{ + partial class SampleView + { + internal global::Controls.CustomTextBox UserNameTextBox { get; set; } + internal global::Avalonia.Controls.TextBlock UserNameValidation { get; set; } + internal global::Avalonia.Controls.TextBox PasswordTextBox { get; set; } + internal global::Avalonia.Controls.TextBlock PasswordValidation { get; set; } + internal global::Avalonia.Controls.ListBox AwesomeListView { get; set; } + internal global::Avalonia.Controls.TextBox ConfirmPasswordTextBox { get; set; } + internal global::Avalonia.Controls.TextBlock ConfirmPasswordValidation { get; set; } + internal global::Avalonia.Controls.Button SignUpButton { get; set; } + internal global::Avalonia.Controls.TextBlock CompoundValidation { get; set; } + + public void InitializeComponent(bool loadXaml = true) + { + if (loadXaml) + { + AvaloniaXamlLoader.Load(this); + } + +#if DEBUG + this.AttachDevTools(); +#endif + + UserNameTextBox = this.FindControl("UserNameTextBox"); + UserNameValidation = this.FindControl("UserNameValidation"); + PasswordTextBox = this.FindControl("PasswordTextBox"); + PasswordValidation = this.FindControl("PasswordValidation"); + AwesomeListView = this.FindControl("AwesomeListView"); + ConfirmPasswordTextBox = this.FindControl("ConfirmPasswordTextBox"); + ConfirmPasswordValidation = this.FindControl("ConfirmPasswordValidation"); + SignUpButton = this.FindControl("SignUpButton"); + CompoundValidation = this.FindControl("CompoundValidation"); + } + } +} diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/xNamedControl.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/xNamedControl.txt new file mode 100644 index 0000000000..bcfcd11625 --- /dev/null +++ b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/xNamedControl.txt @@ -0,0 +1,26 @@ +// + +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Sample.App +{ + partial class SampleView + { + internal global::Avalonia.Controls.TextBox UserNameTextBox { get; set; } + + public void InitializeComponent(bool loadXaml = true) + { + if (loadXaml) + { + AvaloniaXamlLoader.Load(this); + } + +#if DEBUG + this.AttachDevTools(); +#endif + + UserNameTextBox = this.FindControl("UserNameTextBox"); + } + } +} diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/xNamedControls.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/xNamedControls.txt new file mode 100644 index 0000000000..a731f1d04a --- /dev/null +++ b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedDevTools/xNamedControls.txt @@ -0,0 +1,30 @@ +// + +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Sample.App +{ + partial class SampleView + { + internal global::Avalonia.Controls.TextBox UserNameTextBox { get; set; } + internal global::Avalonia.Controls.TextBox PasswordTextBox { get; set; } + internal global::Avalonia.Controls.Button SignUpButton { get; set; } + + public void InitializeComponent(bool loadXaml = true) + { + if (loadXaml) + { + AvaloniaXamlLoader.Load(this); + } + +#if DEBUG + this.AttachDevTools(); +#endif + + UserNameTextBox = this.FindControl("UserNameTextBox"); + PasswordTextBox = this.FindControl("PasswordTextBox"); + SignUpButton = this.FindControl("SignUpButton"); + } + } +} diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/AttachedProps.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/AttachedProps.txt similarity index 100% rename from src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/AttachedProps.txt rename to src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/AttachedProps.txt diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/CustomControls.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/CustomControls.txt similarity index 100% rename from src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/CustomControls.txt rename to src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/CustomControls.txt diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/DataTemplates.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/DataTemplates.txt similarity index 100% rename from src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/DataTemplates.txt rename to src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/DataTemplates.txt diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/FieldModifier.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/FieldModifier.txt similarity index 100% rename from src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/FieldModifier.txt rename to src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/FieldModifier.txt diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/InitializeComponentCode.cs b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/InitializeComponentCode.cs similarity index 88% rename from src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/InitializeComponentCode.cs rename to src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/InitializeComponentCode.cs index 31283c80d8..caefd5e1e7 100644 --- a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/InitializeComponentCode.cs +++ b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/InitializeComponentCode.cs @@ -2,7 +2,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -namespace Avalonia.NameGenerator.Tests.InitializeComponent.GeneratedCode +namespace Avalonia.NameGenerator.Tests.InitializeComponent.GeneratedInitializeComponent { public static class InitializeComponentCode { @@ -22,7 +22,9 @@ namespace Avalonia.NameGenerator.Tests.InitializeComponent.GeneratedCode var assembly = typeof(XamlXNameResolverTests).Assembly; var fullResourceName = assembly .GetManifestResourceNames() - .First(name => name.Contains("InitializeComponent") && name.EndsWith(generatedCodeResourceName)); + .First(name => name.Contains("InitializeComponent") && + name.Contains("GeneratedInitializeComponent") && + name.EndsWith(generatedCodeResourceName)); await using var stream = assembly.GetManifestResourceStream(fullResourceName); using var reader = new StreamReader(stream!); diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/NamedControl.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/NamedControl.txt similarity index 100% rename from src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/NamedControl.txt rename to src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/NamedControl.txt diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/NamedControls.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/NamedControls.txt similarity index 100% rename from src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/NamedControls.txt rename to src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/NamedControls.txt diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/NoNamedControls.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/NoNamedControls.txt similarity index 100% rename from src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/NoNamedControls.txt rename to src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/NoNamedControls.txt diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/SignUpView.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/SignUpView.txt similarity index 100% rename from src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/SignUpView.txt rename to src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/SignUpView.txt diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/xNamedControl.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/xNamedControl.txt similarity index 100% rename from src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/xNamedControl.txt rename to src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/xNamedControl.txt diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/xNamedControls.txt b/src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/xNamedControls.txt similarity index 100% rename from src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedCode/xNamedControls.txt rename to src/Avalonia.NameGenerator.Tests/InitializeComponent/GeneratedInitializeComponent/xNamedControls.txt diff --git a/src/Avalonia.NameGenerator.Tests/InitializeComponent/InitializeComponentTests.cs b/src/Avalonia.NameGenerator.Tests/InitializeComponent/InitializeComponentTests.cs index 61afb6a2af..6604629d32 100644 --- a/src/Avalonia.NameGenerator.Tests/InitializeComponent/InitializeComponentTests.cs +++ b/src/Avalonia.NameGenerator.Tests/InitializeComponent/InitializeComponentTests.cs @@ -1,7 +1,8 @@ using System.Threading.Tasks; using Avalonia.NameGenerator.Compiler; using Avalonia.NameGenerator.Generator; -using Avalonia.NameGenerator.Tests.InitializeComponent.GeneratedCode; +using Avalonia.NameGenerator.Tests.InitializeComponent.GeneratedDevTools; +using Avalonia.NameGenerator.Tests.InitializeComponent.GeneratedInitializeComponent; using Avalonia.NameGenerator.Tests.OnlyProperties.GeneratedCode; using Avalonia.NameGenerator.Tests.Views; using Microsoft.CodeAnalysis.CSharp; @@ -12,24 +13,39 @@ namespace Avalonia.NameGenerator.Tests.InitializeComponent public class InitializeComponentTests { [Theory] - [InlineData(InitializeComponentCode.NamedControl, View.NamedControl)] - [InlineData(InitializeComponentCode.NamedControls, View.NamedControls)] - [InlineData(InitializeComponentCode.XNamedControl, View.XNamedControl)] - [InlineData(InitializeComponentCode.XNamedControls, View.XNamedControls)] - [InlineData(InitializeComponentCode.NoNamedControls, View.NoNamedControls)] - [InlineData(InitializeComponentCode.CustomControls, View.CustomControls)] - [InlineData(InitializeComponentCode.DataTemplates, View.DataTemplates)] - [InlineData(InitializeComponentCode.SignUpView, View.SignUpView)] - [InlineData(InitializeComponentCode.AttachedProps, View.AttachedProps)] - [InlineData(InitializeComponentCode.FieldModifier, View.FieldModifier)] - public async Task Should_Generate_FindControl_Refs_From_Avalonia_Markup_File(string expectation, string markup) + [InlineData(InitializeComponentCode.NamedControl, View.NamedControl, false)] + [InlineData(InitializeComponentCode.NamedControls, View.NamedControls, false)] + [InlineData(InitializeComponentCode.XNamedControl, View.XNamedControl, false)] + [InlineData(InitializeComponentCode.XNamedControls, View.XNamedControls, false)] + [InlineData(InitializeComponentCode.NoNamedControls, View.NoNamedControls, false)] + [InlineData(InitializeComponentCode.CustomControls, View.CustomControls, false)] + [InlineData(InitializeComponentCode.DataTemplates, View.DataTemplates, false)] + [InlineData(InitializeComponentCode.SignUpView, View.SignUpView, false)] + [InlineData(InitializeComponentCode.AttachedProps, View.AttachedProps, false)] + [InlineData(InitializeComponentCode.FieldModifier, View.FieldModifier, false)] + [InlineData(DevToolsCode.NamedControl, View.NamedControl, true)] + [InlineData(DevToolsCode.NamedControls, View.NamedControls, true)] + [InlineData(DevToolsCode.XNamedControl, View.XNamedControl, true)] + [InlineData(DevToolsCode.XNamedControls, View.XNamedControls, true)] + [InlineData(DevToolsCode.NoNamedControls, View.NoNamedControls, true)] + [InlineData(DevToolsCode.CustomControls, View.CustomControls, true)] + [InlineData(DevToolsCode.DataTemplates, View.DataTemplates, true)] + [InlineData(DevToolsCode.SignUpView, View.SignUpView, true)] + [InlineData(DevToolsCode.AttachedProps, View.AttachedProps, true)] + [InlineData(DevToolsCode.FieldModifier, View.FieldModifier, true)] + public async Task Should_Generate_FindControl_Refs_From_Avalonia_Markup_File( + string expectation, + string markup, + bool devToolsMode) { + var excluded = devToolsMode ? null : "Avalonia.Diagnostics"; var compilation = - View.CreateAvaloniaCompilation() + View.CreateAvaloniaCompilation(excluded) .WithCustomTextBox(); + var types = new RoslynTypeSystem(compilation); var classResolver = new XamlXViewResolver( - new RoslynTypeSystem(compilation), + types, MiniCompiler.CreateDefault( new RoslynTypeSystem(compilation), MiniCompiler.AvaloniaXmlnsDefinitionAttribute)); @@ -39,12 +55,15 @@ namespace Avalonia.NameGenerator.Tests.InitializeComponent var nameResolver = new XamlXNameResolver(); var names = nameResolver.ResolveNames(classInfo.Xaml); - var generator = new InitializeComponentCodeGenerator(); + var generator = new InitializeComponentCodeGenerator(types); var code = generator .GenerateCode("SampleView", "Sample.App", names) .Replace("\r", string.Empty); - var expected = await InitializeComponentCode.Load(expectation); + var expected = devToolsMode + ? await DevToolsCode.Load(expectation) + : await InitializeComponentCode.Load(expectation); + CSharpSyntaxTree.ParseText(code); Assert.Equal(expected.Replace("\r", string.Empty), code); } diff --git a/src/Avalonia.NameGenerator.Tests/Views/View.cs b/src/Avalonia.NameGenerator.Tests/Views/View.cs index c15e381d32..c2e4bd085a 100644 --- a/src/Avalonia.NameGenerator.Tests/Views/View.cs +++ b/src/Avalonia.NameGenerator.Tests/Views/View.cs @@ -34,7 +34,7 @@ namespace Avalonia.NameGenerator.Tests.Views return await reader.ReadToEndAsync(); } - public static CSharpCompilation CreateAvaloniaCompilation() + public static CSharpCompilation CreateAvaloniaCompilation(string excludedPattern = null) { var compilation = CSharpCompilation .Create("AvaloniaLib", options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) @@ -48,7 +48,9 @@ namespace Avalonia.NameGenerator.Tests.Views var avaloniaAssemblyDirectory = Path.GetDirectoryName(avaloniaAssemblyLocation); var avaloniaAssemblyReferences = Directory .EnumerateFiles(avaloniaAssemblyDirectory!) - .Where(file => file.EndsWith(".dll") && file.Contains("Avalonia")) + .Where(file => file.EndsWith(".dll") && + file.Contains("Avalonia") && + (string.IsNullOrWhiteSpace(excludedPattern) || !file.Contains(excludedPattern))) .Select(file => MetadataReference.CreateFromFile(file)) .ToList(); diff --git a/src/Avalonia.NameGenerator/Compiler/RoslynTypeSystem.cs b/src/Avalonia.NameGenerator/Compiler/RoslynTypeSystem.cs index 7919137292..11f3482c5d 100644 --- a/src/Avalonia.NameGenerator/Compiler/RoslynTypeSystem.cs +++ b/src/Avalonia.NameGenerator/Compiler/RoslynTypeSystem.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -26,31 +27,19 @@ namespace Avalonia.NameGenerator.Compiler public IReadOnlyList Assemblies => _assemblies; - public IXamlAssembly FindAssembly(string substring) => _assemblies[0]; + public IXamlAssembly FindAssembly(string name) => + Assemblies + .FirstOrDefault(a => string.Equals(a.Name, name, StringComparison.OrdinalIgnoreCase)); - public IXamlType FindType(string name) - { - foreach (var assembly in _assemblies) - { - var type = assembly.FindType(name); - if (type != null) - return type; - } - - return null; - } + public IXamlType FindType(string name) => + _assemblies + .Select(assembly => assembly.FindType(name)) + .FirstOrDefault(type => type != null); - public IXamlType FindType(string name, string assembly) - { - foreach (var assemblyInstance in _assemblies) - { - var type = assemblyInstance.FindType(name); - if (type != null) - return type; - } - - return null; - } + public IXamlType FindType(string name, string assembly) => + _assemblies + .Select(assemblyInstance => assemblyInstance.FindType(name)) + .FirstOrDefault(type => type != null); } public class RoslynAssembly : IXamlAssembly diff --git a/src/Avalonia.NameGenerator/Domain/INameGenerator.cs b/src/Avalonia.NameGenerator/Domain/INameGenerator.cs index 9b12fdfe39..9581d5a0f7 100644 --- a/src/Avalonia.NameGenerator/Domain/INameGenerator.cs +++ b/src/Avalonia.NameGenerator/Domain/INameGenerator.cs @@ -8,15 +8,5 @@ namespace Avalonia.NameGenerator.Domain IReadOnlyList GenerateNameReferences(IEnumerable additionalFiles); } - internal record GeneratedPartialClass - { - public string FileName { get; } - public string Content { get; } - - public GeneratedPartialClass(string fileName, string content) - { - FileName = fileName; - Content = content; - } - } + internal record GeneratedPartialClass(string FileName, string Content); } \ No newline at end of file diff --git a/src/Avalonia.NameGenerator/Domain/INameResolver.cs b/src/Avalonia.NameGenerator/Domain/INameResolver.cs index 09f9037403..64f1730441 100644 --- a/src/Avalonia.NameGenerator/Domain/INameResolver.cs +++ b/src/Avalonia.NameGenerator/Domain/INameResolver.cs @@ -8,17 +8,5 @@ namespace Avalonia.NameGenerator.Domain IReadOnlyList ResolveNames(XamlDocument xaml); } - internal record ResolvedName - { - public string TypeName { get; } - public string Name { get; } - public string FieldModifier { get; } - - public ResolvedName(string typeName, string name, string fieldModifier) - { - TypeName = typeName; - Name = name; - FieldModifier = fieldModifier; - } - } + internal record ResolvedName(string TypeName, string Name, string FieldModifier); } \ No newline at end of file diff --git a/src/Avalonia.NameGenerator/Domain/IViewResolver.cs b/src/Avalonia.NameGenerator/Domain/IViewResolver.cs index 9d619e759c..72ad2c35ee 100644 --- a/src/Avalonia.NameGenerator/Domain/IViewResolver.cs +++ b/src/Avalonia.NameGenerator/Domain/IViewResolver.cs @@ -7,17 +7,5 @@ namespace Avalonia.NameGenerator.Domain ResolvedView ResolveView(string xaml); } - internal record ResolvedView - { - public XamlDocument Xaml { get; } - public string ClassName { get; } - public string Namespace { get; } - - public ResolvedView(string className, string nameSpace, XamlDocument xaml) - { - ClassName = className; - Namespace = nameSpace; - Xaml = xaml; - } - } + internal record ResolvedView(string ClassName, string Namespace, XamlDocument Xaml); } \ No newline at end of file diff --git a/src/Avalonia.NameGenerator/Domain/IsExternalInit.cs b/src/Avalonia.NameGenerator/Domain/IsExternalInit.cs new file mode 100644 index 0000000000..a2f2622a84 --- /dev/null +++ b/src/Avalonia.NameGenerator/Domain/IsExternalInit.cs @@ -0,0 +1,5 @@ +// ReSharper disable once CheckNamespace +namespace System.Runtime.CompilerServices +{ + internal static class IsExternalInit { } +} \ No newline at end of file diff --git a/src/Avalonia.NameGenerator/AvaloniaNameSourceGenerator.cs b/src/Avalonia.NameGenerator/Generator.cs similarity index 99% rename from src/Avalonia.NameGenerator/AvaloniaNameSourceGenerator.cs rename to src/Avalonia.NameGenerator/Generator.cs index b174691cf7..b40ac14079 100644 --- a/src/Avalonia.NameGenerator/AvaloniaNameSourceGenerator.cs +++ b/src/Avalonia.NameGenerator/Generator.cs @@ -32,14 +32,14 @@ namespace Avalonia.NameGenerator private static INameGenerator CreateNameGenerator(GeneratorExecutionContext context) { var options = new GeneratorOptions(context); + var types = new RoslynTypeSystem((CSharpCompilation)context.Compilation); var defaultFieldModifier = options.AvaloniaNameGeneratorDefaultFieldModifier.ToString().ToLowerInvariant(); ICodeGenerator generator = options.AvaloniaNameGeneratorBehavior switch { Behavior.OnlyProperties => new OnlyPropertiesCodeGenerator(), - Behavior.InitializeComponent => new InitializeComponentCodeGenerator(), + Behavior.InitializeComponent => new InitializeComponentCodeGenerator(types), _ => throw new ArgumentOutOfRangeException() }; - var types = new RoslynTypeSystem((CSharpCompilation)context.Compilation); var compiler = MiniCompiler.CreateDefault(types, MiniCompiler.AvaloniaXmlnsDefinitionAttribute); return new AvaloniaNameGenerator( new GlobPatternGroup(options.AvaloniaNameGeneratorFilterByPath), diff --git a/src/Avalonia.NameGenerator/Generator/InitializeComponentCodeGenerator.cs b/src/Avalonia.NameGenerator/Generator/InitializeComponentCodeGenerator.cs index 330885d72e..b3ac709119 100644 --- a/src/Avalonia.NameGenerator/Generator/InitializeComponentCodeGenerator.cs +++ b/src/Avalonia.NameGenerator/Generator/InitializeComponentCodeGenerator.cs @@ -1,21 +1,34 @@ using System.Collections.Generic; -using System.Linq; using Avalonia.NameGenerator.Domain; +using XamlX.TypeSystem; namespace Avalonia.NameGenerator.Generator { internal class InitializeComponentCodeGenerator: ICodeGenerator { - public string GenerateCode(string className, string nameSpace, IEnumerable names) + private readonly bool _attachDevTools; + private const string AttachDevToolsCodeBlock = @" +#if DEBUG + this.AttachDevTools(); +#endif +"; + + public InitializeComponentCodeGenerator(IXamlTypeSystem types) + { + _attachDevTools = types.FindAssembly("Avalonia.Diagnostics") != null; + } + + public string GenerateCode(string className, string nameSpace, IEnumerable names) { var properties = new List(); var initializations = new List(); - foreach (var info in names) + foreach (var (typeName, name, fieldModifier) in names) { - properties.Add($" {info.FieldModifier} global::{info.TypeName} {info.Name} {{ get; set; }}"); - initializations.Add($" {info.Name} = this.FindControl(\"{info.Name}\");"); + properties.Add($" {fieldModifier} global::{typeName} {name} {{ get; set; }}"); + initializations.Add($" {name} = this.FindControl(\"{name}\");"); } - + + var devToolsBlock = _attachDevTools ? AttachDevToolsCodeBlock : string.Empty; return $@"// using Avalonia.Controls; @@ -33,7 +46,7 @@ namespace {nameSpace} {{ AvaloniaXamlLoader.Load(this); }} - +{devToolsBlock} {string.Join("\n", initializations)} }} }} diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 543ce5f816..70fc6f54b2 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -21,6 +21,7 @@ +