Skip to content

Commit 0d9a596

Browse files
[XSG] avoid generating CB twice (#32242)
After some measurment, XSG took 25s on Xaml.UnitTests. code behind file were generated twice. generating once only shave 10s (40%) of XSG time
1 parent 930099a commit 0d9a596

File tree

3 files changed

+32
-17
lines changed

3 files changed

+32
-17
lines changed

src/Controls/src/SourceGen/CodeBehindGenerator.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Xml;
88

99
using Microsoft.CodeAnalysis;
10+
using Microsoft.CodeAnalysis.CSharp;
1011
using Microsoft.CodeAnalysis.Text;
1112

1213
using Microsoft.Maui.Controls.Xaml;
@@ -32,6 +33,10 @@ public void Initialize(IncrementalGeneratorInitializationContext initContext)
3233
.WithComparer(new CompilationReferencesComparer())
3334
.WithTrackingName(TrackingNames.ReferenceCompilationProvider);
3435

36+
var referenceTypeCacheProvider = referenceCompilationProvider
37+
.Select(GetTypeCache)
38+
.WithTrackingName(TrackingNames.ReferenceTypeCacheProvider);
39+
3540
var xmlnsDefinitionsProvider = referenceCompilationProvider
3641
.Select(GetAssemblyAttributes)
3742
.WithTrackingName(TrackingNames.XmlnsDefinitionsProvider);
@@ -57,27 +62,27 @@ public void Initialize(IncrementalGeneratorInitializationContext initContext)
5762
.Where(static p => p?.Kind == "Css")
5863
.WithTrackingName(TrackingNames.CssProjectItemProvider);
5964

60-
var referenceTypeCacheProvider = referenceCompilationProvider
61-
.Select(GetTypeCache)
62-
.WithTrackingName(TrackingNames.ReferenceTypeCacheProvider);
63-
6465
var xamlSourceProviderForCB = xamlProjectItemProviderForCB
6566
.Combine(xmlnsDefinitionsProvider, referenceTypeCacheProvider, referenceCompilationProvider)
67+
.Select(GetSource)
6668
.WithTrackingName(TrackingNames.XamlSourceProviderForCB);
6769

6870
var compilationWithCodeBehindProvider = xamlSourceProviderForCB
69-
.Select(GetSyntaxTree)
7071
.Collect()
7172
.Combine(referenceCompilationProvider)
7273
.Select(static (t, ct) =>
7374
{
7475
var compilation = t.Right;
75-
foreach (var tree in t.Left)
76+
var options = compilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions;
77+
foreach (var (source, xamlItem, diagnostics) in t.Left)
7678
{
7779
ct.ThrowIfCancellationRequested();
7880

79-
if (tree is not null)
81+
if (source is not null)
82+
{
83+
var tree = CSharpSyntaxTree.ParseText(source, options: options, cancellationToken: ct);
8084
compilation = compilation.AddSyntaxTrees(tree);
85+
}
8186
}
8287
return compilation;
8388
})
@@ -95,12 +100,15 @@ public void Initialize(IncrementalGeneratorInitializationContext initContext)
95100
// Register the XAML pipeline for CodeBehind
96101
initContext.RegisterSourceOutput(xamlSourceProviderForCB, static (sourceProductionContext, provider) =>
97102
{
98-
var (xamlItem, xmlnsCache, typeCache, compilation) = provider;
103+
var (source, xamlItem, diagnostics) = provider;
99104

100105
try
101106
{
102-
var code = CodeBehindCodeWriter.GenerateXamlCodeBehind(xamlItem, compilation, sourceProductionContext.ReportDiagnostic, sourceProductionContext.CancellationToken, xmlnsCache, typeCache);
103-
sourceProductionContext.AddSource(GetHintName(xamlItem?.ProjectItem, "sg"), code);
107+
if (diagnostics != null)
108+
foreach (var diag in diagnostics)
109+
sourceProductionContext.ReportDiagnostic(diag);
110+
if (source != null)
111+
sourceProductionContext.AddSource(GetHintName(xamlItem?.ProjectItem, "sg"), source);
104112
}
105113
catch (Exception e)
106114
{

src/Controls/src/SourceGen/GeneratorHelpers.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -365,19 +365,25 @@ static void SimplifyOnPlatform(XmlNode node, string? targetFramework, XmlNamespa
365365

366366
public static IDictionary<XmlType, ITypeSymbol> GetTypeCache(Compilation compilation, CancellationToken cancellationToken) => new Dictionary<XmlType, ITypeSymbol>();
367367

368-
public static SyntaxTree? GetSyntaxTree((XamlProjectItemForCB? xamlItem, AssemblyCaches xmlnsCache, IDictionary<XmlType, ITypeSymbol> typeCache, Compilation compilation) tuple, CancellationToken cancellationToken)
368+
public static (string? source, XamlProjectItemForCB? xamlItem, IList<Diagnostic>? diagnostics) GetSource((XamlProjectItemForCB? xamlItem, AssemblyCaches xmlnsCache, IDictionary<XmlType, ITypeSymbol> typeCache, Compilation compilation) tuple, CancellationToken cancellationToken)
369369
{
370-
var options = tuple.compilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions;
370+
cancellationToken.ThrowIfCancellationRequested();
371+
var (xamlItem, xmlnsCache, typeCache, compilation) = tuple;
372+
373+
string? code = null;
374+
List<Diagnostic>? diagnostics = null;
375+
void reportDiagnostic(Diagnostic diagnostic) => (diagnostics ??= new List<Diagnostic>()).Add(diagnostic);
371376
try
372377
{
373-
var code = CodeBehindCodeWriter.GenerateXamlCodeBehind(tuple.xamlItem, tuple.compilation, null, cancellationToken, tuple.xmlnsCache, tuple.typeCache);
374-
return CSharpSyntaxTree.ParseText(code, options: options, cancellationToken: cancellationToken);
378+
code = CodeBehindCodeWriter.GenerateXamlCodeBehind(xamlItem, compilation, reportDiagnostic, cancellationToken, xmlnsCache, typeCache);
375379
}
376-
catch (Exception)
380+
catch (Exception e)
377381
{
382+
var location = xamlItem?.ProjectItem?.RelativePath is not null ? Location.Create(xamlItem.ProjectItem.RelativePath, new TextSpan(), new LinePositionSpan()) : null;
383+
reportDiagnostic(Diagnostic.Create(Descriptors.XamlParserError, location, e.Message));
378384
}
379-
return null;
380-
}
385+
return (code, xamlItem, diagnostics);
386+
}
381387

382388
/// <summary>
383389
/// Formats a value as a culture-independent C# literal for source generation.

src/Controls/tests/Xaml.UnitTests/Controls.Xaml.UnitTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<DisableMSBuildAssemblyCopyCheck>true</DisableMSBuildAssemblyCopyCheck>
1212
<MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation>
1313
<DefineConstants>$(DefineConstants);MauiAllowImplicitXmlnsDeclaration</DefineConstants>
14+
<ReportAnalyzer>true</ReportAnalyzer>
1415
<!-- We can't yet disable the namescope generation, ConstraintTypeConverter and ReferenceTypeConverter need to be ported to sourcegen
1516
<DefineConstants>$(DefineConstants);_MAUIXAML_SG_NAMESCOPE_DISABLE</DefineConstants>
1617
-->

0 commit comments

Comments
 (0)