From 560e9b393c5027560e9350c83aff4abc3ba790e6 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Fri, 2 Oct 2020 18:00:17 -0400 Subject: [PATCH] feat: Add support for C# 9.0 source generators --- .vsts-ci.yml | 4 + build/Uno.WinUI.nuspec | 45 +- ...ure-devops-wasm-cs9-preview-validation.yml | 39 ++ .../Uno.UI.Lottie/Uno.UI.Lottie.Skia.csproj | 6 +- .../Uno.UI.Lottie/Uno.UI.Lottie.Wasm.csproj | 6 +- src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.csproj | 6 +- src/Directory.Build.props | 13 +- src/Directory.Build.targets | 12 +- .../SamplesApp.Skia.Tizen.csproj | 1 - .../SamplesApp.Skia/SamplesApp.Skia.csproj | 1 - .../SamplesApp.UITests.csproj | 1 - .../SamplesApp.Wasm/SamplesApp.Wasm.csproj | 1 - .../BindableTypeProvidersGenerationTask.cs | 52 +- .../Content/Uno.UI.SourceGenerators.props | 538 +++++++++++------- .../DependencyObjectGenerator.cs | 30 +- .../DependencyPropertyGenerator.cs | 24 +- .../Helpers/AnalyzerSuppressions.cs | 4 +- .../Helpers/DependenciesInitializer.cs | 34 ++ .../Helpers/DesignTimeHelper.cs | 33 ++ .../GeneratorExecutionContextExtensions.cs | 70 +++ .../Helpers/RoslynMetadataHelper.cs | 64 +-- .../NativeCtor/NativeCtorsGenerator.cs | 34 +- .../RemoteControl/RemoteControlGenerator.cs | 59 +- .../TSBindings/TSBindingsGenerator.cs | 104 ++-- .../Uno.UI.SourceGenerators.csproj | 24 +- .../XamlGenerator/PlatformHelper.cs | 26 +- .../XamlCodeGeneration.Telemetry.cs | 17 +- .../XamlGenerator/XamlCodeGeneration.cs | 111 ++-- .../XamlGenerator/XamlCodeGenerator.cs | 41 +- .../XamlFileGenerator.Reflection.cs | 17 +- .../XamlGenerator/XamlFileGenerator.cs | 9 +- .../XamlGenerationTests.Core.csproj | 4 - .../XamlGenerationTests.csproj | 4 - .../sourcegenerators.local.props | 3 - .../Uno.UI.DualScreen.csproj | 4 - src/Uno.UI.FluentTheme/FluentMerge.targets | 1 - src/Uno.UI.Maps/Uno.UI.Maps.csproj | 4 - .../Uno.UI.RuntimeTests.Skia.csproj | 1 - .../Uno.UI.RuntimeTests.Wasm.csproj | 1 - .../Uno.UI.RuntimeTests.csproj | 1 - .../Uno.UI.Tests.Performance.csproj | 4 - .../Uno.UI.Tests.ViewLibrary.csproj | 1 - src/Uno.UI.Tests/Uno.UI.Tests.csproj | 1 - src/Uno.UI.Toolkit/Uno.UI.Toolkit.Skia.csproj | 4 - src/Uno.UI.Toolkit/Uno.UI.Toolkit.Wasm.csproj | 4 - src/Uno.UI.Toolkit/Uno.UI.Toolkit.csproj | 3 - .../Uno.UI.Wasm.Tests.csproj | 4 - src/Uno.UI/Uno.UI.Skia.csproj | 4 +- src/Uno.UI/Uno.UI.Wasm.csproj | 1 - src/Uno.UI/Uno.UI.csproj | 3 +- 50 files changed, 959 insertions(+), 519 deletions(-) create mode 100644 build/ci/.azure-devops-wasm-cs9-preview-validation.yml create mode 100644 src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/DependenciesInitializer.cs create mode 100644 src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/DesignTimeHelper.cs create mode 100644 src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/GeneratorExecutionContextExtensions.cs diff --git a/.vsts-ci.yml b/.vsts-ci.yml index 20cf4b8b9540..46f57ce70293 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -65,6 +65,10 @@ jobs: parameters: vmImage: '$(linuxVMImage)' +- template: build/ci/.azure-devops-wasm-cs9-preview-validation.yml + parameters: + vmImage: '$(linuxVMImage)' + - template: build/ci/.azure-devops-macos.yml parameters: vmImage: '$(macOSVMImage)' diff --git a/build/Uno.WinUI.nuspec b/build/Uno.WinUI.nuspec index 9d944d5dcea6..4e366a7c0d94 100644 --- a/build/Uno.WinUI.nuspec +++ b/build/Uno.WinUI.nuspec @@ -22,7 +22,7 @@ - + @@ -33,7 +33,7 @@ - + @@ -41,7 +41,7 @@ - + @@ -49,7 +49,7 @@ - + @@ -57,7 +57,7 @@ - + @@ -248,16 +248,31 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/ci/.azure-devops-wasm-cs9-preview-validation.yml b/build/ci/.azure-devops-wasm-cs9-preview-validation.yml new file mode 100644 index 000000000000..1f7125010450 --- /dev/null +++ b/build/ci/.azure-devops-wasm-cs9-preview-validation.yml @@ -0,0 +1,39 @@ +parameters: + vmImage: '' + +jobs: +- job: Wasm_cs9_preview_Build + container: nv-bionic-wasm + + pool: + vmImage: ${{ parameters.vmImage }} + + variables: + NUGET_PACKAGES: $(build.sourcesdirectory)/.nuget + + steps: + - checkout: self + clean: true + + - bash: | + msbuild /r /p:Configuration=Release /p:LangVersion=preview /p:UnoUIUseRoslynSourceGenerators=true /p:MicrosoftNetCompilerVersionOverride=3.8.0-3.final src/SamplesApp/SamplesApp.Wasm/SamplesApp.Wasm.csproj /bl:$(build.artifactstagingdirectory)/build-cs9-preview-$(GitVersion.FullSemVer).binlog + + displayName: 'Build sample app' + + - task: CopyFiles@2 + displayName: 'Publish Wasm Site' + condition: always() + inputs: + SourceFolder: $(build.sourcesdirectory)/src/SamplesApp/SamplesApp.Wasm/bin/Release/netstandard2.0/dist + Contents: '**/*.*' + TargetFolder: $(build.artifactstagingdirectory)/site-cs9-preview + CleanTargetFolder: false + OverWrite: false + flattenFolders: false + + - task: PublishBuildArtifacts@1 + condition: always() + inputs: + PathtoPublish: $(build.artifactstagingdirectory) + ArtifactName: wasm-uitest-binaries + ArtifactType: Container diff --git a/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.Skia.csproj b/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.Skia.csproj index b06e42ddd301..89741fa9405c 100644 --- a/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.Skia.csproj +++ b/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.Skia.csproj @@ -15,7 +15,7 @@ - + @@ -25,10 +25,6 @@ - - ..\..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) - - diff --git a/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.Wasm.csproj b/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.Wasm.csproj index 12e325c6ae56..27cba43685a1 100644 --- a/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.Wasm.csproj +++ b/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.Wasm.csproj @@ -25,7 +25,7 @@ - + @@ -37,10 +37,6 @@ - - ..\..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) - - diff --git a/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.csproj b/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.csproj index 2896ce435080..174855d508a9 100644 --- a/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.csproj +++ b/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.csproj @@ -34,7 +34,7 @@ - + @@ -57,10 +57,6 @@ - - ..\..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) - - diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 1cc0372a290e..0c0fadb3d6a8 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -21,8 +21,6 @@ true true - 8.0 - 255.255.255.255 @@ -42,6 +40,17 @@ $(DefineConstants);HAS_UNO_WINUI + + 8.0 + + + false + + - - + + @@ -48,6 +48,14 @@ + + + + all + runtime; build; native; contentfiles; analyzers + + + diff --git a/src/SamplesApp/SamplesApp.Skia.Tizen/SamplesApp.Skia.Tizen.csproj b/src/SamplesApp/SamplesApp.Skia.Tizen/SamplesApp.Skia.Tizen.csproj index f3382e4cf658..46e1846d6e54 100644 --- a/src/SamplesApp/SamplesApp.Skia.Tizen/SamplesApp.Skia.Tizen.csproj +++ b/src/SamplesApp/SamplesApp.Skia.Tizen/SamplesApp.Skia.Tizen.csproj @@ -5,7 +5,6 @@ tizen50 Exe $(DefineConstants);__TIZEN__; - 8.0 diff --git a/src/SamplesApp/SamplesApp.Skia/SamplesApp.Skia.csproj b/src/SamplesApp/SamplesApp.Skia/SamplesApp.Skia.csproj index 9ea0e87311a2..fb2e94de7e87 100644 --- a/src/SamplesApp/SamplesApp.Skia/SamplesApp.Skia.csproj +++ b/src/SamplesApp/SamplesApp.Skia/SamplesApp.Skia.csproj @@ -2,7 +2,6 @@ netstandard2.0 - latest $(DefineConstants);__SKIA__;HAS_UNO;UNO_REFERENCE_API true Skia diff --git a/src/SamplesApp/SamplesApp.UITests/SamplesApp.UITests.csproj b/src/SamplesApp/SamplesApp.UITests/SamplesApp.UITests.csproj index afe6d5cdad2b..8bb49bac4498 100644 --- a/src/SamplesApp/SamplesApp.UITests/SamplesApp.UITests.csproj +++ b/src/SamplesApp/SamplesApp.UITests/SamplesApp.UITests.csproj @@ -2,7 +2,6 @@ net47 - 8.0 diff --git a/src/SamplesApp/SamplesApp.Wasm/SamplesApp.Wasm.csproj b/src/SamplesApp/SamplesApp.Wasm/SamplesApp.Wasm.csproj index f673085edc5f..860eac45459a 100644 --- a/src/SamplesApp/SamplesApp.Wasm/SamplesApp.Wasm.csproj +++ b/src/SamplesApp/SamplesApp.Wasm/SamplesApp.Wasm.csproj @@ -5,7 +5,6 @@ netstandard2.0 $(DefineConstants);__WASM__;HAS_UNO;UNO_REFERENCE_API NU1701,CS1998 - 8.0 true true WebAssembly diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/BindableTypeProviders/BindableTypeProvidersGenerationTask.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/BindableTypeProviders/BindableTypeProvidersGenerationTask.cs index e5a803e7728e..f6c3406aee81 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/BindableTypeProviders/BindableTypeProvidersGenerationTask.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/BindableTypeProviders/BindableTypeProvidersGenerationTask.cs @@ -9,18 +9,26 @@ using System.Xml.Serialization; using System.Collections; using System.Diagnostics; -using Uno.SourceGeneration; using Microsoft.CodeAnalysis; -using Microsoft.Build.Execution; -using Uno.UI.SourceGenerators.XamlGenerator; using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.Text; +using Uno.Roslyn; +using Uno.UI.SourceGenerators.XamlGenerator; using Microsoft.CodeAnalysis.CSharp; using System.Reflection.Metadata.Ecma335; +using Uno.UI.SourceGenerators.Helpers; + +#if NETFRAMEWORK +using Uno.SourceGeneration; +#endif namespace Uno.UI.SourceGenerators.BindableTypeProviders { +#if NETFRAMEWORK [GenerateAfter("Uno.ImmutableGenerator")] - public class BindableTypeProvidersSourceGenerator : SourceGenerator +#endif + [Generator] + public class BindableTypeProvidersSourceGenerator : ISourceGenerator { private const string TypeMetadataConfigFile = "TypeMetadataConfig.xml"; @@ -40,17 +48,23 @@ public class BindableTypeProvidersSourceGenerator : SourceGenerator public INamedTypeSymbol _stringSymbol { get; private set; } - public override void Execute(SourceGeneratorContext context) + public void Initialize(GeneratorInitializationContext context) { + } + + public void Execute(GeneratorExecutionContext context) + { + DependenciesInitializer.Init(context); + try { - if (PlatformHelper.IsValidPlatform(context)) - { - var project = context.GetProjectInstance(); - if (IsApplication(project)) + if (PlatformHelper.IsValidPlatform(context) + && !DesignTimeHelper.IsDesignTime(context)) + { + if (IsApplication(context)) { - _defaultNamespace = project.GetPropertyValue("RootNamespace"); + _defaultNamespace = context.GetMSBuildPropertyValue("RootNamespace"); _bindableAttributeSymbol = FindBindableAttributes(context); _dependencyPropertySymbol = context.Compilation.GetTypeByMetadataName(XamlConstants.Types.DependencyProperty); @@ -73,7 +87,7 @@ from module in sym.Modules modules = modules.Concat(context.Compilation.SourceModule); - context.AddCompilationUnit("BindableMetadata", GenerateTypeProviders(modules)); + context.AddSource("BindableMetadata", GenerateTypeProviders(modules)); } } } @@ -90,16 +104,16 @@ from module in sym.Modules } } - private static INamedTypeSymbol[] FindBindableAttributes(SourceGeneratorContext context) => - SymbolFinder.FindDeclarationsAsync(context.Project, "BindableAttribute", false).Result.OfType().ToArray(); + private static INamedTypeSymbol[] FindBindableAttributes(GeneratorExecutionContext context) => + context.Compilation.GetSymbolsWithName("BindableAttribute", SymbolFilter.Type).OfType().ToArray(); - private bool IsApplication(ProjectInstance projectInstance) + private bool IsApplication(GeneratorExecutionContext context) { - var isAndroidApp = projectInstance.GetPropertyValue("AndroidApplication")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; - var isiOSApp = projectInstance.GetPropertyValue("ProjectTypeGuids")?.Equals("{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", StringComparison.OrdinalIgnoreCase) ?? false; - var ismacOSApp = projectInstance.GetPropertyValue("ProjectTypeGuids")?.Equals("{A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", StringComparison.OrdinalIgnoreCase) ?? false; - var isExe = projectInstance.GetPropertyValue("OutputType")?.Equals("Exe", StringComparison.OrdinalIgnoreCase) ?? false; - var isUnoHead = projectInstance.GetPropertyValue("IsUnoHead")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; + var isAndroidApp = context.GetMSBuildPropertyValue("AndroidApplication")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; + var isiOSApp = context.GetMSBuildPropertyValue("ProjectTypeGuidsProperty")?.Equals("{FEACFBD2-3405-455C-9665-78FE426C6842},{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", StringComparison.OrdinalIgnoreCase) ?? false; + var ismacOSApp = context.GetMSBuildPropertyValue("ProjectTypeGuidsProperty")?.Equals("{A3F8F2AB-B479-4A4A-A458-A89E7DC349F1},{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", StringComparison.OrdinalIgnoreCase) ?? false; + var isExe = context.GetMSBuildPropertyValue("OutputType")?.Equals("Exe", StringComparison.OrdinalIgnoreCase) ?? false; + var isUnoHead = context.GetMSBuildPropertyValue("IsUnoHead")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; return isAndroidApp || (isiOSApp && isExe) diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/Content/Uno.UI.SourceGenerators.props b/src/SourceGenerators/Uno.UI.SourceGenerators/Content/Uno.UI.SourceGenerators.props index d5028c420261..64feaf325e23 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/Content/Uno.UI.SourceGenerators.props +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/Content/Uno.UI.SourceGenerators.props @@ -1,217 +1,367 @@  - - - + + + - - $(MSBuildThisFileDirectory)..\tools + + <_isRoslynAnalyzerAvailable Condition="'$(MSBuildVersion)' >= '16.8'">true + <_canUseRoslynAnalyzer Condition="'$(LangVersion)' == 'preview' or ('$(LangVersion)'!='' and $(LangVersion.Contains('.')) and '$(LangVersion)'>='9.0')">true + true - ios - android - macos - wasm - skia - net461 - + ios + android + macos + wasm + skia + net461 + - + + + + + + + + + + + $(UnoUIUseRoslynSourceGenerators) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_UnoUIGeneratorsBinPathInPackage>$(MSBuildThisFileDirectory)..\tools\uno-sourcegen + <_UnoUIGeneratorsBinPathInSource>$(MSBuildThisFileDirectory)..\bin\$(Configuration)\net461 + $(_UnoUIGeneratorsBinPathInPackage) + $(_UnoUIGeneratorsBinPathInSource) + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - True - False - - - - - - - DataSource - - - - - ItemsSource - - - - - ItemsSource - - - - - ItemsSource - - - - - ItemsSource - - - - - Password - - - - - Text - Uno.UI.Behaviors.TextBoxBehavior.Text - nVentive.Umbrella.Views.Behaviors.TextBoxBehavior.Text - nVentive.Umbrella.Views.Behaviors.PasswordBoxBehavior.Text - - - - - Command - - - - - IsChecked - - - - - Command - - - - - Text - - - - - Source - - - - - Date - - - - - ItemsSource - - - + + True + False + - - - - - - - - - - - - - - - - - - - - - - + + + + + DataSource + + + + + ItemsSource + + + + + ItemsSource + + + + + ItemsSource + + + + + ItemsSource + + + + + Password + + + + + Text + Uno.UI.Behaviors.TextBoxBehavior.Text + nVentive.Umbrella.Views.Behaviors.TextBoxBehavior.Text + nVentive.Umbrella.Views.Behaviors.PasswordBoxBehavior.Text + + + + + Command + + + + + IsChecked + + + + + Command + + + + + Text + + + + + Source + + + + + Date + + + + + ItemsSource + + + - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_AdditionalFilesCleanup Include="@(AdditionalFiles)" /> + + + + + + + + + + + + + + <_AnalyzerToRemove Include="@(Analyzer)" Condition="'%(FileName)'=='Uno.UI.SourceGenerators'" /> + + + diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/DependencyObject/DependencyObjectGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/DependencyObject/DependencyObjectGenerator.cs index 4efdb232a6c7..720d108e70a9 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/DependencyObject/DependencyObjectGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/DependencyObject/DependencyObjectGenerator.cs @@ -5,16 +5,32 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Uno.Extensions; -using Uno.SourceGeneration; using Uno.UI.SourceGenerators.Helpers; using Uno.UI.SourceGenerators.XamlGenerator; +using Uno.Roslyn; +using System.Diagnostics; +using System.Reflection; +using System.IO; + +#if NETFRAMEWORK +using Uno.SourceGeneration; +#endif namespace Uno.UI.SourceGenerators.DependencyObject { - public class DependencyObjectGenerator : SourceGenerator + [Generator] + public class DependencyObjectGenerator : ISourceGenerator { - public override void Execute(SourceGeneratorContext context) + public void Initialize(GeneratorInitializationContext context) { + // Debugger.Launch(); + // No initialization required for this one + + } + + public void Execute(GeneratorExecutionContext context) + { + DependenciesInitializer.Init(context); if (PlatformHelper.IsValidPlatform(context)) { var visitor = new SerializationMethodsGenerator(context); @@ -24,7 +40,7 @@ public override void Execute(SourceGeneratorContext context) private class SerializationMethodsGenerator : SymbolVisitor { - private readonly SourceGeneratorContext _context; + private readonly GeneratorExecutionContext _context; private readonly INamedTypeSymbol _dependencyObjectSymbol; private readonly INamedTypeSymbol _unoViewgroupSymbol; private readonly INamedTypeSymbol _iosViewSymbol; @@ -37,7 +53,7 @@ private class SerializationMethodsGenerator : SymbolVisitor private readonly INamedTypeSymbol _iFrameworkElementSymbol; - public SerializationMethodsGenerator(SourceGeneratorContext context) + public SerializationMethodsGenerator(GeneratorExecutionContext context) { _context = context; @@ -130,7 +146,7 @@ private void ProcessType(INamedTypeSymbol typeSymbol) } } - _context.AddCompilationUnit(HashBuilder.BuildIDFromSymbol(typeSymbol), builder.ToString()); + _context.AddSource(HashBuilder.BuildIDFromSymbol(typeSymbol), builder.ToString()); } } @@ -310,7 +326,7 @@ protected override void OnAttachedToWindow() #if {implementsIFrameworkElement} //Is IFrameworkElement OnLoading(); OnLoaded(); -#endif +#endif _loadActions.ForEach(a => a.Item1()); BinderAttachedToWindow(); }} diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/DependencyObject/DependencyPropertyGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/DependencyObject/DependencyPropertyGenerator.cs index a3e18fde6f6a..75cde1bf21fc 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/DependencyObject/DependencyPropertyGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/DependencyObject/DependencyPropertyGenerator.cs @@ -3,23 +3,33 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Drawing.Text; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Uno.Extensions; -using Uno.SourceGeneration; +using Uno.Roslyn; using Uno.UI.SourceGenerators.Helpers; using Uno.UI.SourceGenerators.XamlGenerator; +#if NETFRAMEWORK +using Uno.SourceGeneration; +#endif + namespace Uno.UI.SourceGenerators.DependencyObject { - public class DependencyPropertyGenerator : SourceGenerator + [Generator] + public class DependencyPropertyGenerator : ISourceGenerator { - public override void Execute(SourceGeneratorContext context) + public void Initialize(GeneratorInitializationContext context) { + } + + public void Execute(GeneratorExecutionContext context) + { + DependenciesInitializer.Init(context); + if (PlatformHelper.IsValidPlatform(context)) { var visitor = new SerializationMethodsGenerator(context); @@ -29,12 +39,12 @@ public override void Execute(SourceGeneratorContext context) private class SerializationMethodsGenerator : SymbolVisitor { - private readonly SourceGeneratorContext _context; + private readonly GeneratorExecutionContext _context; private readonly INamedTypeSymbol _generatedDependencyPropertyAttributeSymbol; private readonly INamedTypeSymbol _dependencyPropertyChangedEventArgsSymbol; private readonly INamedTypeSymbol _dependencyObjectSymbol; - public SerializationMethodsGenerator(SourceGeneratorContext context) + public SerializationMethodsGenerator(GeneratorExecutionContext context) { _context = context; @@ -153,7 +163,7 @@ private void ProcessType(INamedTypeSymbol typeSymbol) } } - _context.AddCompilationUnit(HashBuilder.BuildIDFromSymbol(typeSymbol), builder.ToString()); + _context.AddSource(HashBuilder.BuildIDFromSymbol(typeSymbol), builder.ToString()); } } } diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/AnalyzerSuppressions.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/AnalyzerSuppressions.cs index 3bb074634918..17b9f310a313 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/AnalyzerSuppressions.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/AnalyzerSuppressions.cs @@ -14,7 +14,7 @@ internal class AnalyzerSuppressionsGenerator internal static void Generate(IIndentedStringBuilder writer, string[] analyzerSuppressions) { var suppresses = from suppress in analyzerSuppressions - let parts = suppress.Split('|') + let parts = suppress.Split('|','-') where parts.Length == 2 let category = parts[0] let id = parts[1] @@ -26,4 +26,4 @@ internal static void Generate(IIndentedStringBuilder writer, string[] analyzerSu } } } -} \ No newline at end of file +} diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/DependenciesInitializer.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/DependenciesInitializer.cs new file mode 100644 index 000000000000..920cb0001759 --- /dev/null +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/DependenciesInitializer.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq; +using System.IO; +using System.Reflection; +using Uno.Extensions; +using Uno.Extensions.Specialized; +using Uno.Roslyn; +using System.Diagnostics; +using Microsoft.CodeAnalysis; + +#if NETFRAMEWORK +using Uno.SourceGeneration; +#endif + +namespace Uno.UI.SourceGenerators +{ + internal class DependenciesInitializer + { + internal static void Init(GeneratorExecutionContext context) + { + // Kept until dependencies can be added automatically and this is not needed anymore + // + // var assemblyName = typeof(DependenciesInitializer).Assembly.GetName().Name; + // var baseAnalyzer = context.GetMSBuildItems("Analyzer") + // .Where(f => f.Identity.EndsWith(assemblyName + ".dll")) + // .FirstOrDefault(); + + // if (baseAnalyzer != null) + // { + // Assembly.LoadFrom(Path.Combine(Path.GetDirectoryName(baseAnalyzer.Identity), "Uno.Core.dll")); + // } + } + } +} diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/DesignTimeHelper.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/DesignTimeHelper.cs new file mode 100644 index 000000000000..645a3ff4f1ec --- /dev/null +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/DesignTimeHelper.cs @@ -0,0 +1,33 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Uno.Roslyn; + +#if NETFRAMEWORK +using Uno.SourceGeneration; +#endif + +namespace Uno.UI.SourceGenerators.Helpers +{ + public static class DesignTimeHelper + { + public static bool IsDesignTime(GeneratorExecutionContext context) + { +#if NETFRAMEWORK + // Uno source generators do not support design-time generation + return false; +#else + var isBuildingProjectValue = context.GetMSBuildPropertyValue("BuildingProject"); // legacy projects + var isDesignTimeBuildValue = context.GetMSBuildPropertyValue("DesignTimeBuild"); // sdk-style projects + + return string.Equals(isBuildingProjectValue, "false", StringComparison.OrdinalIgnoreCase) + || string.Equals(isDesignTimeBuildValue, "true", StringComparison.OrdinalIgnoreCase); +#endif + } + } +} diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/GeneratorExecutionContextExtensions.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/GeneratorExecutionContextExtensions.cs new file mode 100644 index 000000000000..8dca24ce2074 --- /dev/null +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/GeneratorExecutionContextExtensions.cs @@ -0,0 +1,70 @@ +#nullable enable +#if NETSTANDARD +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; + +namespace Uno.Roslyn +{ + internal static class GeneratorExecutionContextExtensions + { + private const string SourceItemGroupMetadata = "build_metadata.AdditionalFiles.SourceItemGroup"; + public static void AddCompilationUnit(this GeneratorExecutionContext context, string name, string source) + => context.AddSource(name, SourceText.From(source, Encoding.UTF8)); + + public static string GetMSBuildPropertyValue( + this GeneratorExecutionContext context, + string name, + string defaultValue = "") + { + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue($"build_property.{name}", out var value); + return value ?? defaultValue; + } + public static IEnumerable GetMSBuildItems(this GeneratorExecutionContext context, string name) + => context + .AdditionalFiles + .Where(f => context.AnalyzerConfigOptions + .GetOptions(f) + .TryGetValue(SourceItemGroupMetadata, out var sourceItemGroup) + && sourceItemGroup == name) + .Select(f => new MSBuildItem(f, context)) + .ToArray(); + } + + /// + /// Defines an Item provided by MSBuild + /// + public class MSBuildItem + { + private readonly AdditionalText File; + private readonly GeneratorExecutionContext Context; + + internal MSBuildItem(AdditionalText file, GeneratorExecutionContext context) + { + File = file; + Context = context; + } + + /// + /// Gets the Identity (EvalutatedInclude) of the item + /// + public string Identity => File.Path; + + /// + /// Gets a metadata for this item + /// + /// The name of the metadata + /// The metadata value + public string GetMetadataValue(string name) + { + Context.AnalyzerConfigOptions + .GetOptions(File) + .TryGetValue("build_metadata.AdditionalFiles." + name, out var metadataValue); + + return string.IsNullOrEmpty(metadataValue) ? "" : metadataValue!; + } + } +} +#endif diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/RoslynMetadataHelper.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/RoslynMetadataHelper.cs index 2255bf5f6599..db11f743c852 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/RoslynMetadataHelper.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/RoslynMetadataHelper.cs @@ -8,7 +8,12 @@ using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.Build.Execution; + +#if NETFRAMEWORK +using Uno.SourceGeneration; +using ISourceGenerator = Uno.SourceGeneration.SourceGenerator; +using GeneratorExecutionContext = Uno.SourceGeneration.GeneratorExecutionContext; +#endif namespace Uno.Roslyn { @@ -16,7 +21,6 @@ internal class RoslynMetadataHelper { private const string AdditionalTypesFileName = "additionalTypes.cs"; - private Project _project; private readonly INamedTypeSymbol _nullableSymbol; private string[] _additionalTypes; private readonly Dictionary _legacyTypes; @@ -25,24 +29,32 @@ internal class RoslynMetadataHelper private readonly Func _getAllDerivingTypes; private readonly Func _getAllTypesAttributedWith; private readonly Dictionary _additionalTypesMap; - + private readonly Dictionary> _namedSymbolsLookup; public Compilation Compilation { get; } - public string AssemblyName => _project.AssemblyName; + public string AssemblyName => Compilation.AssemblyName; - public RoslynMetadataHelper(string configuration, Compilation sourceCompilation, ProjectInstance projectInstance, Project roslynProject, string[] additionalTypes = null, Dictionary legacyTypes = null) + public RoslynMetadataHelper(string configuration, GeneratorExecutionContext context, Dictionary legacyTypes = null) { - Compilation = GenerateAdditionalTypes(sourceCompilation); + Compilation = context.Compilation; _additionalTypesMap = GenerateAdditionalTypesMap(); _findTypesByName = Funcs.Create(SourceFindTypesByName).AsLockedMemoized(); _findTypeByFullName = Funcs.Create(SourceFindTypeByFullName).AsLockedMemoized(); - _additionalTypes = additionalTypes ?? new string[0]; + _additionalTypes = new string[0]; _legacyTypes = BuildLegacyTypes(legacyTypes); _getAllDerivingTypes = Funcs.Create(GetAllDerivingTypes).AsLockedMemoized(); _getAllTypesAttributedWith = Funcs.Create(SourceGetAllTypesAttributedWith).AsLockedMemoized(); - _project = roslynProject; _nullableSymbol = Compilation.GetTypeByMetadataName("System.Nullable`1"); + + var refs = from metadataReference in Compilation.References + let assembly = Compilation.GetAssemblyOrModuleSymbol(metadataReference) as IAssemblySymbol + where assembly != null + from type in assembly.GlobalNamespace.GetNamespaceTypes() + group type by type.Name into names + select new { names.Key, names }; + + _namedSymbolsLookup = refs.ToDictionary(k => k.Key, p => p.names.AsEnumerable()); } private Dictionary GenerateAdditionalTypesMap() @@ -90,31 +102,6 @@ private Dictionary BuildLegacyTypes(Dictionary t.Key, t => t.Metadata) ?? new Dictionary(); - private Compilation GenerateAdditionalTypes(Compilation sourceCompilation) - { - if (_additionalTypes?.Any() ?? false) - { - var sb = new StringBuilder(); - sb.AppendLine("class __test__ {"); - - int index = 0; - foreach (var type in _additionalTypes) - { - sb.AppendLine($"{type} __{index++};"); - } - - sb.AppendLine("}"); - - _project = _project.AddDocument(AdditionalTypesFileName, sb.ToString()).Project; - - return _project.GetCompilationAsync().Result; - } - else - { - return sourceCompilation; - } - } - public ITypeSymbol[] FindTypesByName(string name) { if (name.HasValue()) @@ -134,16 +121,19 @@ private ITypeSymbol[] SourceFindTypesByName(string name) // This validation ensure that the project has been loaded. Compilation.Validation().NotNull("Compilation"); - var results = SymbolFinder - .FindDeclarationsAsync(_project, name, ignoreCase: false, filter: SymbolFilter.Type) - .Result; + var results = Compilation.GetSymbolsWithName(name, SymbolFilter.Type).OfType(); + + if(_namedSymbolsLookup.TryGetValue(name, out var metadataResults)) + { + results = results.Concat(metadataResults); + } return results .OfType() .Where(r => r.Kind != SymbolKind.ErrorType && r.TypeArguments.Length == 0) // Apply legacy .Where(r => legacyType == null || r.OriginalDefinition.Name != name || Equals(r.OriginalDefinition, legacyType)) - .ToArray(); + .ToArray() ?? new ITypeSymbol[0]; } return Array.Empty(); diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/NativeCtor/NativeCtorsGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/NativeCtor/NativeCtorsGenerator.cs index b252cdd1dcad..b5d4df320fd2 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/NativeCtor/NativeCtorsGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/NativeCtor/NativeCtorsGenerator.cs @@ -4,22 +4,36 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using Uno.SourceGeneration; +using Uno.Roslyn; using Uno.UI.SourceGenerators.Helpers; +#if NETFRAMEWORK +using Uno.SourceGeneration; +#endif + namespace Uno.UI.SourceGenerators.NativeCtor { - public class NativeCtorsGenerator : SourceGenerator + [Generator] + public class NativeCtorsGenerator : ISourceGenerator { - public override void Execute(SourceGeneratorContext context) - { - var visitor = new SerializationMethodsGenerator(context); - visitor.Visit(context.Compilation.SourceModule); + public void Initialize(GeneratorInitializationContext context) + { + } + + public void Execute(GeneratorExecutionContext context) + { + if (!DesignTimeHelper.IsDesignTime(context)) + { + DependenciesInitializer.Init(context); + + var visitor = new SerializationMethodsGenerator(context); + visitor.Visit(context.Compilation.SourceModule); + } } private class SerializationMethodsGenerator : SymbolVisitor { - private readonly SourceGeneratorContext _context; + private readonly GeneratorExecutionContext _context; private readonly Compilation _comp; private readonly INamedTypeSymbol _iosViewSymbol; private readonly INamedTypeSymbol _macosViewSymbol; @@ -73,7 +87,7 @@ partial class {1} }} "; - public SerializationMethodsGenerator(SourceGeneratorContext context) + public SerializationMethodsGenerator(GeneratorExecutionContext context) { _context = context; @@ -132,7 +146,7 @@ private void ProcessType(INamedTypeSymbol typeSymbol) if (nativeCtor == null) { - _context.AddCompilationUnit( + _context.AddSource( HashBuilder.BuildIDFromSymbol(typeSymbol), string.Format( BaseClassFormat, @@ -155,7 +169,7 @@ private void ProcessType(INamedTypeSymbol typeSymbol) if (nativeCtor == null) { - _context.AddCompilationUnit( + _context.AddSource( HashBuilder.BuildIDFromSymbol(typeSymbol), string.Format( BaseClassFormat, diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/RemoteControl/RemoteControlGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/RemoteControl/RemoteControlGenerator.cs index 11a64c49db29..a3cdaafa54c7 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/RemoteControl/RemoteControlGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/RemoteControl/RemoteControlGenerator.cs @@ -1,4 +1,3 @@ -using Microsoft.Build.Execution; using Microsoft.CodeAnalysis; using System; using System.Collections.Generic; @@ -10,19 +9,31 @@ using System.Text; using System.Threading.Tasks; using Uno.Extensions; -using Uno.SourceGeneration; +using Uno.Roslyn; using Uno.UI.SourceGenerators.Helpers; +#if NETFRAMEWORK +using Uno.SourceGeneration; +#endif + namespace Uno.UI.SourceGenerators.RemoteControl { - public class RemoteControlGenerator : SourceGenerator + [Generator] + public class RemoteControlGenerator : ISourceGenerator { - public override void Execute(SourceGeneratorContext context) + public void Initialize(GeneratorInitializationContext context) + { + } + + public void Execute(GeneratorExecutionContext context) { + DependenciesInitializer.Init(context); + if ( - context.GetProjectInstance().GetPropertyValue("Configuration") == "Debug" + !DesignTimeHelper.IsDesignTime(context) + && context.GetMSBuildPropertyValue("Configuration") == "Debug" && IsRemoteControlClientInstalled(context) - && IsApplication(context.GetProjectInstance())) + && IsApplication(context)) { var sb = new IndentedStringBuilder(); @@ -40,20 +51,19 @@ public override void Execute(SourceGeneratorContext context) BuildEndPointAttribute(context, sb); BuildSearchPaths(context, sb); - context.AddCompilationUnit("RemoteControl", sb.ToString()); + context.AddSource("RemoteControl", sb.ToString()); } } - private static bool IsRemoteControlClientInstalled(SourceGeneratorContext context) + private static bool IsRemoteControlClientInstalled(GeneratorExecutionContext context) => context.Compilation.GetTypeByMetadataName("Uno.UI.RemoteControl.RemoteControlClient") != null; - private static void BuildSearchPaths(SourceGeneratorContext context, IndentedStringBuilder sb) + private static void BuildSearchPaths(GeneratorExecutionContext context, IndentedStringBuilder sb) { - var projectInstance = context.GetProjectInstance(); - sb.AppendLineInvariant($"[assembly: global::Uno.UI.RemoteControl.ProjectConfigurationAttribute("); - sb.AppendLineInvariant($"@\"{projectInstance.FullPath}\",\n"); + sb.AppendLineInvariant($"@\"{context.GetMSBuildPropertyValue("MSBuildProjectFullPath")}\",\n"); + var msBuildProjectDirectory = context.GetMSBuildPropertyValue("MSBuildProjectDirectory"); var sources = new[] { "Page", "ApplicationDefinition", @@ -61,10 +71,9 @@ private static void BuildSearchPaths(SourceGeneratorContext context, IndentedStr }; IEnumerable BuildSearchPath(string s) - => projectInstance - .GetItems(s) - .Select(v => v.EvaluatedInclude) - .Select(v => Path.IsPathRooted(v) ? v : Path.Combine(projectInstance.Directory, v)); + => context + .GetMSBuildItems(s) + .Select(v => Path.IsPathRooted(v.Identity) ? v.Identity : Path.Combine(msBuildProjectDirectory, v.Identity)); var xamlPaths = from item in sources.SelectMany(BuildSearchPath) select Path.GetDirectoryName(item); @@ -77,16 +86,16 @@ IEnumerable BuildSearchPath(string s) } - private static void BuildEndPointAttribute(SourceGeneratorContext context, IndentedStringBuilder sb) + private static void BuildEndPointAttribute(GeneratorExecutionContext context, IndentedStringBuilder sb) { - var unoRemoteControlPort = context.GetProjectInstance().GetPropertyValue("UnoRemoteControlPort"); + var unoRemoteControlPort = context.GetMSBuildPropertyValue("UnoRemoteControlPort"); if (string.IsNullOrEmpty(unoRemoteControlPort)) { unoRemoteControlPort = "0"; } - var unoRemoteControlHost = context.GetProjectInstance().GetPropertyValue("UnoRemoteControlHost"); + var unoRemoteControlHost = context.GetMSBuildPropertyValue("UnoRemoteControlHost"); if (string.IsNullOrEmpty(unoRemoteControlHost)) { @@ -105,13 +114,13 @@ private static void BuildEndPointAttribute(SourceGeneratorContext context, Inden } } - private bool IsApplication(ProjectInstance projectInstance) + private bool IsApplication(GeneratorExecutionContext context) { - var isAndroidApp = projectInstance.GetPropertyValue("AndroidApplication")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; - var isiOSApp = projectInstance.GetPropertyValue("ProjectTypeGuids")?.Equals("{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", StringComparison.OrdinalIgnoreCase) ?? false; - var ismacOSApp = projectInstance.GetPropertyValue("ProjectTypeGuids")?.Equals("{A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", StringComparison.OrdinalIgnoreCase) ?? false; - var isExe = projectInstance.GetPropertyValue("OutputType")?.Equals("Exe", StringComparison.OrdinalIgnoreCase) ?? false; - var isUnoHead = projectInstance.GetPropertyValue("IsUnoHead")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; + var isAndroidApp = context.GetMSBuildPropertyValue("AndroidApplication")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; + var isiOSApp = context.GetMSBuildPropertyValue("ProjectTypeGuids")?.Equals("{FEACFBD2-3405-455C-9665-78FE426C6842},{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", StringComparison.OrdinalIgnoreCase) ?? false; + var ismacOSApp = context.GetMSBuildPropertyValue("ProjectTypeGuids")?.Equals("{A3F8F2AB-B479-4A4A-A458-A89E7DC349F1},{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", StringComparison.OrdinalIgnoreCase) ?? false; + var isExe = context.GetMSBuildPropertyValue("OutputType")?.Equals("Exe", StringComparison.OrdinalIgnoreCase) ?? false; + var isUnoHead = context.GetMSBuildPropertyValue("IsUnoHead")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; return isAndroidApp || (isiOSApp && isExe) diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/TSBindings/TSBindingsGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/TSBindings/TSBindingsGenerator.cs index f31b43a4a863..2c7be6523d1c 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/TSBindings/TSBindingsGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/TSBindings/TSBindingsGenerator.cs @@ -1,17 +1,27 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Uno.Extensions; +using Uno.Roslyn; +using Uno.UI.SourceGenerators.Helpers; + +#if NETFRAMEWORK using Uno.SourceGeneration; +using Uno.UI.SourceGenerators.Helpers; +#endif namespace Uno.UI.SourceGenerators.TSBindings { - class TSBindingsGenerator : SourceGenerator + [Generator] + class TSBindingsGenerator : ISourceGenerator { private string _bindingsPaths; private string[] _sourceAssemblies; @@ -28,35 +38,43 @@ class TSBindingsGenerator : SourceGenerator private static INamedTypeSymbol _structLayoutSymbol; private static INamedTypeSymbol _interopMessageSymbol; - public override void Execute(SourceGeneratorContext context) + public void Initialize(GeneratorInitializationContext context) { - var project = context.GetProjectInstance(); - _bindingsPaths = project.GetPropertyValue("TSBindingsPath")?.ToString(); - _sourceAssemblies = project.GetItems("TSBindingAssemblySource").Select(s => s.EvaluatedInclude).ToArray(); + } - if(!string.IsNullOrEmpty(_bindingsPaths)) + public void Execute(GeneratorExecutionContext context) + { + DependenciesInitializer.Init(context); + + if (!DesignTimeHelper.IsDesignTime(context)) { - _stringSymbol = context.Compilation.GetTypeByMetadataName("System.String"); - _intSymbol = context.Compilation.GetTypeByMetadataName("System.Int32"); - _floatSymbol = context.Compilation.GetTypeByMetadataName("System.Single"); - _doubleSymbol = context.Compilation.GetTypeByMetadataName("System.Double"); - _byteSymbol = context.Compilation.GetTypeByMetadataName("System.Byte"); - _shortSymbol = context.Compilation.GetTypeByMetadataName("System.Int16"); - _intPtrSymbol = context.Compilation.GetTypeByMetadataName("System.IntPtr"); - _boolSymbol = context.Compilation.GetTypeByMetadataName("System.Boolean"); - _longSymbol = context.Compilation.GetTypeByMetadataName("System.Int64"); - _structLayoutSymbol = context.Compilation.GetTypeByMetadataName(typeof(System.Runtime.InteropServices.StructLayoutAttribute).FullName); - _interopMessageSymbol = context.Compilation.GetTypeByMetadataName("Uno.Foundation.Interop.TSInteropMessageAttribute"); - - var modules = from ext in context.Compilation.ExternalReferences - let sym = context.Compilation.GetAssemblyOrModuleSymbol(ext) as IAssemblySymbol - where _sourceAssemblies.Contains(sym.Name) - from module in sym.Modules - select module; - - modules = modules.Concat(context.Compilation.SourceModule); - - GenerateTSMarshallingLayouts(modules); + _bindingsPaths = context.GetMSBuildPropertyValue("TSBindingsPath")?.ToString(); + _sourceAssemblies = context.GetMSBuildItems("TSBindingAssemblySource").Select(i => i.Identity).ToArray(); + + if (!string.IsNullOrEmpty(_bindingsPaths)) + { + _stringSymbol = context.Compilation.GetTypeByMetadataName("System.String"); + _intSymbol = context.Compilation.GetTypeByMetadataName("System.Int32"); + _floatSymbol = context.Compilation.GetTypeByMetadataName("System.Single"); + _doubleSymbol = context.Compilation.GetTypeByMetadataName("System.Double"); + _byteSymbol = context.Compilation.GetTypeByMetadataName("System.Byte"); + _shortSymbol = context.Compilation.GetTypeByMetadataName("System.Int16"); + _intPtrSymbol = context.Compilation.GetTypeByMetadataName("System.IntPtr"); + _boolSymbol = context.Compilation.GetTypeByMetadataName("System.Boolean"); + _longSymbol = context.Compilation.GetTypeByMetadataName("System.Int64"); + _structLayoutSymbol = context.Compilation.GetTypeByMetadataName(typeof(System.Runtime.InteropServices.StructLayoutAttribute).FullName); + _interopMessageSymbol = context.Compilation.GetTypeByMetadataName("Uno.Foundation.Interop.TSInteropMessageAttribute"); + + var modules = from ext in context.Compilation.ExternalReferences + let sym = context.Compilation.GetAssemblyOrModuleSymbol(ext) as IAssemblySymbol + where _sourceAssemblies.Contains(sym.Name) + from module in sym.Modules + select module; + + modules = modules.Concat(context.Compilation.SourceModule); + + GenerateTSMarshallingLayouts(modules); + } } } @@ -127,13 +145,15 @@ private static IEnumerable GetNamespaceTypes(IModuleSymbol mod } } - private int GetStructPack(INamedTypeSymbol parametersType) + private int GetStructPack(ISymbol parametersType) { // https://github.com/dotnet/roslyn/blob/master/src/Compilers/Core/Portable/Symbols/TypeLayout.cs is not available. - if (parametersType.GetType().GetProperty("Layout", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic) is PropertyInfo info) + var actualSymbol = GetActualSymbol(parametersType); + + if (actualSymbol.GetType().GetProperty("Layout", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic) is PropertyInfo info) { - if (info.GetValue(parametersType) is object typeLayout) + if (info.GetValue(actualSymbol) is { } typeLayout) { if (typeLayout.GetType().GetProperty("Kind", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) is PropertyInfo layoutKingProperty) { @@ -159,12 +179,14 @@ private bool IsMarshalledExplicitly(IFieldSymbol fieldSymbol) { // https://github.com/dotnet/roslyn/blob/0610c79807fa59d0815f2b89e5283cf6d630b71e/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs#L133 is not available. - if (fieldSymbol.GetType().GetProperty( + var actualSymbol = GetActualSymbol(fieldSymbol); + + if (actualSymbol.GetType().GetProperty( "IsMarshalledExplicitly", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic) is PropertyInfo info ) { - if (info.GetValue(fieldSymbol) is bool isMarshalledExplicitly) + if (info.GetValue(actualSymbol) is bool isMarshalledExplicitly) { return isMarshalledExplicitly; } @@ -173,6 +195,24 @@ private bool IsMarshalledExplicitly(IFieldSymbol fieldSymbol) throw new InvalidOperationException($"Failed to IsMarshalledExplicitly, unknown roslyn internal structure"); } + /// + /// Reads the actual symbol as Roslyn 3.6+ wraps symbols and we need access to the original type properties. + /// + /// + /// + private object GetActualSymbol(ISymbol symbol) + { + if (symbol.GetType().GetProperty("UnderlyingSymbol", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic) is PropertyInfo info) + { + if (info.GetValue(symbol) is { } underlyingSymbol) + { + return underlyingSymbol; + } + } + + return symbol; + } + private void GenerateMarshaler(INamedTypeSymbol parametersType, IndentedStringBuilder sb, int packValue) { using (sb.BlockInvariant($"public marshal(pData:number)")) diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/Uno.UI.SourceGenerators.csproj b/src/SourceGenerators/Uno.UI.SourceGenerators/Uno.UI.SourceGenerators.csproj index 8f8f73f36d3d..d4b117f8a584 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/Uno.UI.SourceGenerators.csproj +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/Uno.UI.SourceGenerators.csproj @@ -1,12 +1,13 @@  - net461 + net461;netstandard2.0 Uno.UI.SourceGenerators - false + true true + true - + @@ -41,6 +42,20 @@ + + + + 3.1.6 + + + + 3.8.0-3.final + + + 0.10.1 + + + @@ -108,4 +123,7 @@ + + + diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/PlatformHelper.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/PlatformHelper.cs index ab8ebd34004c..945c1511e06d 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/PlatformHelper.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/PlatformHelper.cs @@ -1,28 +1,30 @@ -#nullable enable + +#nullable enable using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Uno.Roslyn; + +#if NETFRAMEWORK using Uno.SourceGeneration; +#endif namespace Uno.UI.SourceGenerators.XamlGenerator { public class PlatformHelper { - public static bool IsValidPlatform(SourceGeneratorContext context) + public static bool IsValidPlatform(GeneratorExecutionContext context) { - var projectInstance = context.GetProjectInstance(); - - var evaluatedValue = projectInstance - .GetProperty("TargetPlatformIdentifier") - ?.EvaluatedValue ?? ""; + var evaluatedValue = context.GetMSBuildPropertyValue("TargetPlatformIdentifier"); + var useWPF = context.GetMSBuildPropertyValue("UseWPF"); + var projectTypeGuids = context.GetMSBuildPropertyValue("ProjectTypeGuidsProperty"); - var isUAP = evaluatedValue.Equals("UAP", StringComparison.OrdinalIgnoreCase); - var isNetCoreWPF = (projectInstance.GetProperty("UseWPF")?.EvaluatedValue ?? "").Equals("True", StringComparison.OrdinalIgnoreCase); - var isNetCoreDesktop = projectInstance - .GetProperty("ProjectTypeGuids") - ?.EvaluatedValue == "{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"; + var isUAP = evaluatedValue?.Equals("UAP", StringComparison.OrdinalIgnoreCase) ?? false; + var isNetCoreWPF = useWPF?.Equals("True", StringComparison.OrdinalIgnoreCase) ?? false; + var isNetCoreDesktop = projectTypeGuids == "{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"; return !isUAP && !isNetCoreWPF && !isNetCoreDesktop; } diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGeneration.Telemetry.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGeneration.Telemetry.cs index 6ecd9d34010c..acba1302dc86 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGeneration.Telemetry.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGeneration.Telemetry.cs @@ -9,10 +9,15 @@ using Uno.Roslyn; using Microsoft.CodeAnalysis; using Uno.Extensions; -using Microsoft.Build.Execution; using Uno.Logging; using Uno.UI.SourceGenerators.Telemetry; +#if NETFRAMEWORK +using Uno.SourceGeneration; +using ISourceGenerator = Uno.SourceGeneration.SourceGenerator; +using GeneratorExecutionContext = Uno.SourceGeneration.GeneratorExecutionContext; +#endif + namespace Uno.UI.SourceGenerators.XamlGenerator { internal partial class XamlCodeGeneration @@ -25,9 +30,9 @@ internal partial class XamlCodeGeneration || Environment.GetEnvironmentVariable("JENKINS_URL").HasValue() // https://wiki.jenkins.io/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-belowJenkinsSetEnvironmentVariables || Environment.GetEnvironmentVariable("APPVEYOR").HasValue(); // https://www.appveyor.com/docs/environment-variables/ - private void InitTelemetry(ProjectInstance msbProject) + private void InitTelemetry(GeneratorExecutionContext context) { - var telemetryOptOut = msbProject.GetProperty("UnoPlatformTelemetryOptOut")?.EvaluatedValue ?? ""; + var telemetryOptOut = context.GetMSBuildPropertyValue("UnoPlatformTelemetryOptOut"); bool? isTelemetryOptout() => telemetryOptOut.Equals("true", StringComparison.OrdinalIgnoreCase) @@ -99,7 +104,7 @@ private void TrackStartGeneration(XamlFileDefinition[] files) try { // Determine if the Uno.UI solution is built - var isBuildingUno = _projectInstance.GetProperty("MSBuildProjectName")?.EvaluatedValue == "Uno.UI"; + var isBuildingUno = _generatorContext.GetMSBuildPropertyValue("MSBuildProjectName") == "Uno.UI"; _telemetry.TrackEvent( "generate-xaml", @@ -107,7 +112,7 @@ private void TrackStartGeneration(XamlFileDefinition[] files) ("UnoXaml", XamlRedirection.XamlConfig.IsUnoXaml.ToString()), ("IsWasm", _isWasm.ToString()), ("IsDebug", _isDebug.ToString()), - ("TargetFramework", _projectInstance.GetProperty("TargetFramework")?.EvaluatedValue.ToString()), + ("TargetFramework", _generatorContext.GetMSBuildPropertyValue("TargetFramework")?.ToString()), ("UnoRuntime", BuildUnoRuntimeValue()), ("IsBuildingUnoSolution", isBuildingUno.ToString()), ("IsUiAutomationMappingEnabled", _isUiAutomationMappingEnabled.ToString()), @@ -129,7 +134,7 @@ private void TrackStartGeneration(XamlFileDefinition[] files) private string BuildUnoRuntimeValue() { - var constants = _projectInstance.GetProperty("DefineConstants").EvaluatedValue; + var constants = _generatorContext.GetMSBuildPropertyValue("DefineConstantsProperty"); if (constants != null) { diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGeneration.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGeneration.cs index 3f6d84cc4b4e..567225a6264b 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGeneration.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGeneration.cs @@ -9,11 +9,15 @@ using Uno.Roslyn; using Microsoft.CodeAnalysis; using Uno.Extensions; -using Microsoft.Build.Execution; using Uno.Logging; using Uno.UI.SourceGenerators.Telemetry; using Uno.UI.Xaml; -using Microsoft.Build.Utilities; + +#if NETFRAMEWORK +using Microsoft.Build.Execution; +using Uno.SourceGeneration; +using GeneratorExecutionContext = Uno.SourceGeneration.GeneratorExecutionContext; +#endif namespace Uno.UI.SourceGenerators.XamlGenerator { @@ -29,16 +33,19 @@ internal partial class XamlCodeGeneration private readonly bool _isWasm; private readonly string _defaultNamespace; private readonly string[] _assemblySearchPaths; - private readonly RoslynMetadataHelper _metadataHelper; private readonly string[] _excludeXamlNamespaces; private readonly string[] _includeXamlNamespaces; private readonly string[] _analyzerSuppressions; private readonly string[] _resourceFiles; private readonly Dictionary _uiAutomationMappings; - private readonly ProjectInstance _projectInstance; private readonly string _configuration; private readonly bool _isDebug; private readonly bool _outputSourceComments = true; + private readonly RoslynMetadataHelper _metadataHelper; + +#if NETFRAMEWORK + private readonly ProjectInstance _projectInstance; +#endif /// /// If set, code generated from XAML will be annotated with the source method and line # in XamlFileGenerator, for easier debugging. @@ -53,6 +60,7 @@ internal partial class XamlCodeGeneration // Determines if the source generator will skip the inclusion of UseControls in the // visual tree. See https://github.com/unoplatform/uno/issues/61 private bool _skipUserControlsInVisualTree = false; + private readonly GeneratorExecutionContext _generatorContext; private bool IsUnoAssembly => _defaultNamespace == "Uno.UI"; private bool IsUnoFluentAssembly => _defaultNamespace == "Uno.UI.FluentTheme"; @@ -83,7 +91,7 @@ internal partial class XamlCodeGeneration private readonly bool _forceGeneration; #pragma warning restore 649 // Unused member - public XamlCodeGeneration(Compilation sourceCompilation, ProjectInstance msbProject, Project roslynProject) + public XamlCodeGeneration(GeneratorExecutionContext context) { // To easily debug XAML code generation: // 1. Uncomment the line below @@ -92,122 +100,99 @@ public XamlCodeGeneration(Compilation sourceCompilation, ProjectInstance msbProj // - if it's in an external solution, attach the VS instance running Uno.UI // - if you're debugging XAML generation inside the Uno solution, opt to create a new VS instance // - //Debugger.Launch(); - - InitTelemetry(msbProject); + // Debugger.Launch(); + _generatorContext = context; + InitTelemetry(context); - _legacyTypes = msbProject - .GetItems("LegacyTypes") - .Select(i => i.EvaluatedInclude) + _legacyTypes = context + .GetMSBuildPropertyValue("LegacyTypesProperty") + .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToList() - .ToDictionary(fullyQualifiedName => fullyQualifiedName.Split('.').Last()); + .ToDictionary(k => k, fullyQualifiedName => fullyQualifiedName.Split('.').Last()); - _metadataHelper = new RoslynMetadataHelper("Debug", sourceCompilation, msbProject, roslynProject, null, _legacyTypes); + _metadataHelper = new RoslynMetadataHelper("Debug", context, _legacyTypes); _assemblySearchPaths = new string[0]; - _projectInstance = msbProject; - _configuration = msbProject.GetProperty("Configuration")?.EvaluatedValue + _configuration = context.GetMSBuildPropertyValue("Configuration") ?? throw new InvalidOperationException("The configuration property must be provided"); _isDebug = string.Equals(_configuration, "Debug", StringComparison.OrdinalIgnoreCase); - var xamlItems = msbProject.GetItems("Page") - .Concat(msbProject.GetItems("ApplicationDefinition")); + var xamlItems = context.GetMSBuildItems("Page") + .Concat(context.GetMSBuildItems("ApplicationDefinition")); - _xamlSourceFiles = xamlItems.Select(d => d.EvaluatedInclude) - .ToArray(); + _xamlSourceFiles = xamlItems.Select(i => i.Identity).ToArray(); _xamlSourceLinks = xamlItems.Select(GetSourceLink) .ToArray(); - _excludeXamlNamespaces = msbProject - .GetItems("ExcludeXamlNamespaces") - .Select(i => i.EvaluatedInclude) - .ToArray(); + _excludeXamlNamespaces = context.GetMSBuildPropertyValue("ExcludeXamlNamespacesProperty").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - _includeXamlNamespaces = msbProject - .GetItems("IncludeXamlNamespaces") - .Select(i => i.EvaluatedInclude) - .ToArray(); + _includeXamlNamespaces = context.GetMSBuildPropertyValue("IncludeXamlNamespacesProperty").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - _analyzerSuppressions = msbProject - .GetItems("XamlGeneratorAnalyzerSuppressions") - .Select(i => i.EvaluatedInclude) - .ToArray(); + _analyzerSuppressions = context.GetMSBuildPropertyValue("XamlGeneratorAnalyzerSuppressionsProperty").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - _resourceFiles = msbProject - .GetItems("PRIResource") - .Select(i => i.EvaluatedInclude) - .ToArray(); + _resourceFiles = context.GetMSBuildItems("PRIResource").Select(i => i.Identity).ToArray(); - if (bool.TryParse(msbProject.GetProperty("UseUnoXamlParser")?.EvaluatedValue, out var useUnoXamlParser) && useUnoXamlParser) + if (bool.TryParse(context.GetMSBuildPropertyValue("UseUnoXamlParser"), out var useUnoXamlParser) && useUnoXamlParser) { XamlRedirection.XamlConfig.IsUnoXaml = useUnoXamlParser || XamlRedirection.XamlConfig.IsMono; } - if (bool.TryParse(msbProject.GetProperty("UnoSkipUserControlsInVisualTree")?.EvaluatedValue, out var skipUserControlsInVisualTree)) + if (bool.TryParse(context.GetMSBuildPropertyValue("UnoSkipUserControlsInVisualTree"), out var skipUserControlsInVisualTree)) { _skipUserControlsInVisualTree = skipUserControlsInVisualTree; } - if (bool.TryParse(msbProject.GetProperty("ShouldWriteErrorOnInvalidXaml")?.EvaluatedValue, out var shouldWriteErrorOnInvalidXaml)) + if (bool.TryParse(context.GetMSBuildPropertyValue("ShouldWriteErrorOnInvalidXaml"), out var shouldWriteErrorOnInvalidXaml)) { XamlFileGenerator.ShouldWriteErrorOnInvalidXaml = shouldWriteErrorOnInvalidXaml; } - if (!bool.TryParse(msbProject.GetProperty("IsUiAutomationMappingEnabled")?.EvaluatedValue ?? "", out _isUiAutomationMappingEnabled)) + if (!bool.TryParse(context.GetMSBuildPropertyValue("IsUiAutomationMappingEnabled") ?? "", out _isUiAutomationMappingEnabled)) { _isUiAutomationMappingEnabled = false; } - if (bool.TryParse(msbProject.GetProperty("ShouldAnnotateGeneratedXaml")?.EvaluatedValue, out var shouldAnnotateGeneratedXaml)) + if (bool.TryParse(context.GetMSBuildPropertyValue("ShouldAnnotateGeneratedXaml"), out var shouldAnnotateGeneratedXaml)) { _shouldAnnotateGeneratedXaml = shouldAnnotateGeneratedXaml; } _targetPath = Path.Combine( - Path.GetDirectoryName(msbProject.FullPath), - msbProject.GetProperty("IntermediateOutputPath").EvaluatedValue + Path.GetDirectoryName(context.GetMSBuildPropertyValue("MSBuildProjectFullPath")), + context.GetMSBuildPropertyValue("IntermediateOutputPath") ); - _defaultLanguage = msbProject.GetProperty("DefaultLanguage")?.EvaluatedValue; + _defaultLanguage = context.GetMSBuildPropertyValue("DefaultLanguage"); - _analyzerSuppressions = msbProject - .GetItems("XamlGeneratorAnalyzerSuppressions") - .Select(i => i.EvaluatedInclude) - .ToArray(); + _analyzerSuppressions = context.GetMSBuildItems("XamlGeneratorAnalyzerSuppressions").Select(i => i.Identity).ToArray(); - _uiAutomationMappings = msbProject - .GetItems("CustomUiAutomationMemberMapping") + _uiAutomationMappings = context.GetMSBuildItems("CustomUiAutomationMemberMappingAdjusted") .Select(i => new { - Key = i.EvaluatedInclude, - Value = i.MetadataNames - .Select(i.GetMetadataValue) - .FirstOrDefault() - ?.Split() + Key = i.Identity, + Value = i.GetMetadataValue("Mappings") + ?.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(m => m.Trim()) .Where(m => m.HasValueTrimmed()) }) .GroupBy(p => p.Key) .ToDictionary(p => p.Key, p => p.SelectMany(x => x.Value.Safe()).ToArray()); - _defaultNamespace = msbProject.GetPropertyValue("RootNamespace"); + _defaultNamespace = context.GetMSBuildPropertyValue("RootNamespace"); - _isWasm = msbProject.GetProperty("DefineConstants").EvaluatedValue?.Contains("__WASM__") ?? false; + _isWasm = context.GetMSBuildPropertyValue("DefineConstantsProperty")?.Contains("__WASM__") ?? false; } /// /// Get the file location as seen in the IDE, used for ResourceDictionary.Source resolution. /// - private string GetSourceLink(ProjectItemInstance projectItemInstance) + private string GetSourceLink(MSBuildItem projectItemInstance) { - if (projectItemInstance.HasMetadata("Link")) - { - return projectItemInstance.GetMetadataValue("Link"); - } + var value = projectItemInstance.GetMetadataValue("Link"); - return projectItemInstance.EvaluatedInclude; + return value.IsNullOrEmpty() ? projectItemInstance.Identity : value; } public KeyValuePair[] Generate() @@ -502,7 +487,7 @@ private string GenerateGlobalResources(IEnumerable files, Xa using (writer.BlockInvariant("internal static {0} {1} {{get; }} = new {0}()", ParseContextPropertyType, ParseContextPropertyName)) { - writer.AppendLineInvariant("AssemblyName = \"{0}\",", _projectInstance.GetPropertyValue("AssemblyName")); + writer.AppendLineInvariant("AssemblyName = \"{0}\",", _metadataHelper.AssemblyName); } writer.AppendLineInvariant(";"); diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGenerator.cs index 9dbd525e96a5..c49a8a163167 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGenerator.cs @@ -1,22 +1,39 @@ using System; using System.Diagnostics; using System.IO; +using System.Net.Mime; using System.Text; -using Uno.SourceGeneration; +using Microsoft.CodeAnalysis; +using Uno.Roslyn; using Uno.UI.SourceGenerators.Telemetry; +#if NETFRAMEWORK +using Uno.SourceGeneration; +#endif + namespace Uno.UI.SourceGenerators.XamlGenerator { +#if NETFRAMEWORK [GenerateAfter("Uno.UI.SourceGenerators.DependencyObject." + nameof(DependencyObject.DependencyPropertyGenerator))] - public class XamlCodeGenerator : SourceGenerator +#endif + [Generator] + public class XamlCodeGenerator : ISourceGenerator { - public override void Execute(SourceGeneratorContext context) + public void Initialize(GeneratorInitializationContext context) + { + } + + public void Execute(GeneratorExecutionContext context) { - var gen = new XamlCodeGeneration( - context.Compilation, - context.GetProjectInstance(), - context.Project - ); + DependenciesInitializer.Init(context); + + // No initialization required for this one + //if (!Process.GetCurrentProcess().ProcessName.Equals("devenv", StringComparison.OrdinalIgnoreCase)) + { + // Debugger.Launch(); + } + + var gen = new XamlCodeGeneration(context); if (PlatformHelper.IsValidPlatform(context)) { @@ -24,7 +41,13 @@ public override void Execute(SourceGeneratorContext context) foreach (var tree in genereratedTrees) { - context.AddCompilationUnit(tree.Key, tree.Value); + context.AddSource(tree.Key, tree.Value); + + // Uncomment to output the generated files to a separate folder + // var intermediatePath = context.GetMSBuildPropertyValue("IntermediateOutputPath"); + // var path = Path.Combine(intermediatePath, "generated"); + // Directory.CreateDirectory(path); + // File.WriteAllText(Path.Combine(path, tree.Key), tree.Value); } } } diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.Reflection.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.Reflection.cs index 274080c4336a..cdb60668aa6c 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.Reflection.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.Reflection.cs @@ -758,12 +758,26 @@ private INamedTypeSymbol SourceFindTypeByXamlType(XamlType type) { if (type != null) { + // Search first using the explicit XML namespace in known namespaces + + // Remove the namespace conditionals declaration + var trimmedNamespace = type.PreferredXamlNamespace.Split('?').First(); + var clrNamespaces = _knownNamespaces.UnoGetValueOrDefault(trimmedNamespace, new string[0]); + + foreach (var clrNamespace in clrNamespaces) + { + if(_findType(clrNamespace + "." + type.Name) is { } result) + { + return result; + } + } + + // Then use fuzzy lookup var ns = _fileDefinition .Namespaces // Ensure that prefixless declaration (generally xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation") is considered first, otherwise PreferredXamlNamespace matching can go awry .OrderByDescending(n => n.Prefix.IsNullOrEmpty()) .FirstOrDefault(n => n.Namespace == type.PreferredXamlNamespace); - var isKnownNamespace = ns?.Prefix?.HasValue() ?? false; if ( type.PreferredXamlNamespace == XamlConstants.XamlXmlNamespace @@ -773,6 +787,7 @@ private INamedTypeSymbol SourceFindTypeByXamlType(XamlType type) return _findType(XamlConstants.Namespaces.Data + ".Binding"); } + var isKnownNamespace = ns?.Prefix?.HasValue() ?? false; var fullName = isKnownNamespace ? ns.Prefix + ":" + type.Name : type.Name; return _findType(fullName); diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs index 55abadf1b0f4..b378a370ee4e 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs @@ -228,8 +228,8 @@ bool isUnoAssembly _dataBindingSymbol = GetType("Windows.UI.Xaml.Data.Binding"); _styleSymbol = GetType(XamlConstants.Types.Style); _colorSymbol = GetType(XamlConstants.Types.Color); - _androidContentContextSymbol = GetType("Android.Content.Context"); - _androidViewSymbol = GetType("Android.Views.View"); + _androidContentContextSymbol = FindType("Android.Content.Context"); + _androidViewSymbol = FindType("Android.Views.View"); _markupExtensionTypes = _metadataHelper.GetAllTypesDerivingFrom(_markupExtensionSymbol).ToList(); _xamlConversionTypes = _metadataHelper.GetAllTypesAttributedWith(GetType(XamlConstants.Types.CreateFromStringAttribute)).ToList(); @@ -284,7 +284,7 @@ public string GenerateFile() } catch (Exception e) { - throw new Exception("Processing failed for file {0}".InvariantCultureFormat(_fileDefinition.FilePath), e); + throw new Exception($"Processing failed for file {_fileDefinition.FilePath} ({e})", e); } } @@ -555,7 +555,8 @@ private void GenerateResourceLoader(IndentedStringBuilder writer) throw new InvalidOperationException($"The reference {reference.Display} could not be found in {reference.Display}"); } - var asm = Mono.Cecil.AssemblyDefinition.ReadAssembly(reference.Display); + using var stream = File.OpenRead(reference.Display); + var asm = Mono.Cecil.AssemblyDefinition.ReadAssembly(stream); if (asm.MainModule.HasResources && asm.MainModule.Resources.Any(r => r.Name.EndsWith("upri"))) { diff --git a/src/SourceGenerators/XamlGenerationTests.Core/XamlGenerationTests.Core.csproj b/src/SourceGenerators/XamlGenerationTests.Core/XamlGenerationTests.Core.csproj index f75ef91e1d5d..ca44b1442ea6 100644 --- a/src/SourceGenerators/XamlGenerationTests.Core/XamlGenerationTests.Core.csproj +++ b/src/SourceGenerators/XamlGenerationTests.Core/XamlGenerationTests.Core.csproj @@ -37,10 +37,6 @@ - - ..\Uno.UI.SourceGenerators\bin\$(Configuration) - - diff --git a/src/SourceGenerators/XamlGenerationTests/XamlGenerationTests.csproj b/src/SourceGenerators/XamlGenerationTests/XamlGenerationTests.csproj index 67c55dc339c1..c2dd1ebd781c 100644 --- a/src/SourceGenerators/XamlGenerationTests/XamlGenerationTests.csproj +++ b/src/SourceGenerators/XamlGenerationTests/XamlGenerationTests.csproj @@ -59,10 +59,6 @@ - - ..\Uno.UI.SourceGenerators\bin\$(Configuration) - - diff --git a/src/SourceGenerators/sourcegenerators.local.props b/src/SourceGenerators/sourcegenerators.local.props index 1362ce7a9f28..44201dfa71d8 100644 --- a/src/SourceGenerators/sourcegenerators.local.props +++ b/src/SourceGenerators/sourcegenerators.local.props @@ -4,9 +4,6 @@ This file is meant to be used inside of Uno to reference the generators and tasks --> - - $(MSBuildThisFileDirectory)Uno.UI.SourceGenerators\bin\$(Configuration) - diff --git a/src/Uno.UI.DualScreen/Uno.UI.DualScreen.csproj b/src/Uno.UI.DualScreen/Uno.UI.DualScreen.csproj index 5cac741bbb15..bbcd0967a82d 100644 --- a/src/Uno.UI.DualScreen/Uno.UI.DualScreen.csproj +++ b/src/Uno.UI.DualScreen/Uno.UI.DualScreen.csproj @@ -54,10 +54,6 @@ - - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) - - diff --git a/src/Uno.UI.FluentTheme/FluentMerge.targets b/src/Uno.UI.FluentTheme/FluentMerge.targets index c75710e9467c..b9db1630c3ec 100644 --- a/src/Uno.UI.FluentTheme/FluentMerge.targets +++ b/src/Uno.UI.FluentTheme/FluentMerge.targets @@ -73,7 +73,6 @@ - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) $(MSBuildThisFileDirectory)..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow diff --git a/src/Uno.UI.Maps/Uno.UI.Maps.csproj b/src/Uno.UI.Maps/Uno.UI.Maps.csproj index 1640957fe6c7..2ba87e3d1900 100644 --- a/src/Uno.UI.Maps/Uno.UI.Maps.csproj +++ b/src/Uno.UI.Maps/Uno.UI.Maps.csproj @@ -54,10 +54,6 @@ - - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) - - diff --git a/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.Skia.csproj b/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.Skia.csproj index f541e2010b1c..adf87d16cbd2 100644 --- a/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.Skia.csproj +++ b/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.Skia.csproj @@ -55,7 +55,6 @@ $(MSBuildThisFileDirectory)..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) diff --git a/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.Wasm.csproj b/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.Wasm.csproj index 602e85c801be..eb90ac183ac1 100644 --- a/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.Wasm.csproj +++ b/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.Wasm.csproj @@ -71,7 +71,6 @@ $(MSBuildThisFileDirectory)..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) diff --git a/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.csproj b/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.csproj index a951db789d50..df0f50bb1849 100644 --- a/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.csproj +++ b/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.csproj @@ -82,7 +82,6 @@ - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) $(MSBuildThisFileDirectory)..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow diff --git a/src/Uno.UI.Tests.Performance/Uno.UI.Tests.Performance.csproj b/src/Uno.UI.Tests.Performance/Uno.UI.Tests.Performance.csproj index d4a3285f5dde..71dae4f42f50 100644 --- a/src/Uno.UI.Tests.Performance/Uno.UI.Tests.Performance.csproj +++ b/src/Uno.UI.Tests.Performance/Uno.UI.Tests.Performance.csproj @@ -57,10 +57,6 @@ - - - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) - diff --git a/src/Uno.UI.Tests.ViewLibrary/Uno.UI.Tests.ViewLibrary.csproj b/src/Uno.UI.Tests.ViewLibrary/Uno.UI.Tests.ViewLibrary.csproj index bec830897e7a..b26ce2fe59dd 100644 --- a/src/Uno.UI.Tests.ViewLibrary/Uno.UI.Tests.ViewLibrary.csproj +++ b/src/Uno.UI.Tests.ViewLibrary/Uno.UI.Tests.ViewLibrary.csproj @@ -51,7 +51,6 @@ - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) $(MSBuildThisFileDirectory)..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow true diff --git a/src/Uno.UI.Tests/Uno.UI.Tests.csproj b/src/Uno.UI.Tests/Uno.UI.Tests.csproj index dde8f63da508..24b648a2de5f 100644 --- a/src/Uno.UI.Tests/Uno.UI.Tests.csproj +++ b/src/Uno.UI.Tests/Uno.UI.Tests.csproj @@ -70,7 +70,6 @@ - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) $(MSBuildThisFileDirectory)..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow true diff --git a/src/Uno.UI.Toolkit/Uno.UI.Toolkit.Skia.csproj b/src/Uno.UI.Toolkit/Uno.UI.Toolkit.Skia.csproj index 9a37dbd28908..cf31363c0562 100644 --- a/src/Uno.UI.Toolkit/Uno.UI.Toolkit.Skia.csproj +++ b/src/Uno.UI.Toolkit/Uno.UI.Toolkit.Skia.csproj @@ -46,10 +46,6 @@ - - - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) - diff --git a/src/Uno.UI.Toolkit/Uno.UI.Toolkit.Wasm.csproj b/src/Uno.UI.Toolkit/Uno.UI.Toolkit.Wasm.csproj index c4cb8df9bf7c..6811e5798740 100644 --- a/src/Uno.UI.Toolkit/Uno.UI.Toolkit.Wasm.csproj +++ b/src/Uno.UI.Toolkit/Uno.UI.Toolkit.Wasm.csproj @@ -49,10 +49,6 @@ - - - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) - diff --git a/src/Uno.UI.Toolkit/Uno.UI.Toolkit.csproj b/src/Uno.UI.Toolkit/Uno.UI.Toolkit.csproj index be4c36b3c816..18f5cfdd780f 100644 --- a/src/Uno.UI.Toolkit/Uno.UI.Toolkit.csproj +++ b/src/Uno.UI.Toolkit/Uno.UI.Toolkit.csproj @@ -105,9 +105,6 @@ - - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) - diff --git a/src/Uno.UI.Wasm.Tests/Uno.UI.Wasm.Tests.csproj b/src/Uno.UI.Wasm.Tests/Uno.UI.Wasm.Tests.csproj index d791176e6dad..6ad6ff274f1f 100644 --- a/src/Uno.UI.Wasm.Tests/Uno.UI.Wasm.Tests.csproj +++ b/src/Uno.UI.Wasm.Tests/Uno.UI.Wasm.Tests.csproj @@ -37,10 +37,6 @@ _UnoSourceGenerator; $(CompileTypeScriptDependsOn) - - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) - - diff --git a/src/Uno.UI/Uno.UI.Skia.csproj b/src/Uno.UI/Uno.UI.Skia.csproj index 0bfb3e9cf73e..19b3bee23c9f 100644 --- a/src/Uno.UI/Uno.UI.Skia.csproj +++ b/src/Uno.UI/Uno.UI.Skia.csproj @@ -25,8 +25,8 @@ - + all @@ -65,7 +65,6 @@ - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) $(MSBuildThisFileDirectory)..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow _UnoSourceGenerator; $(CompileTypeScriptDependsOn) @@ -108,5 +107,4 @@ TargetFramework - diff --git a/src/Uno.UI/Uno.UI.Wasm.csproj b/src/Uno.UI/Uno.UI.Wasm.csproj index 4b686704baa0..c4a0c3f29d2b 100644 --- a/src/Uno.UI/Uno.UI.Wasm.csproj +++ b/src/Uno.UI/Uno.UI.Wasm.csproj @@ -101,7 +101,6 @@ - ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) $(MSBuildThisFileDirectory)..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow _UnoSourceGenerator; $(CompileTypeScriptDependsOn) diff --git a/src/Uno.UI/Uno.UI.csproj b/src/Uno.UI/Uno.UI.csproj index c7db3f7218e0..095076e9558e 100644 --- a/src/Uno.UI/Uno.UI.csproj +++ b/src/Uno.UI/Uno.UI.csproj @@ -86,7 +86,7 @@ - + @@ -146,7 +146,6 @@ - $(MSBuildThisFileDirectory)..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) $(MSBuildThisFileDirectory)..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow