Skip to content

Commit 61b4999

Browse files
[XSG] enable/disable feature in msbuild (#31349)
* [XSG] option to disable #line info generation Doesn't change the generated IL at the end, but make the generated cs file easir to read, understand, reflect on * [XSG] Param to enabling diagnostics <MauiXamlEnableDiagnostics> property or EnableDiagnostics item metadata. defaults to true for debug * MauiXamlLineInfo * the generated code always require nullable * nowarn * do not default to enablediagnostics on release * rename flag * Release don't have diagnostics, so body is smaller * fix nullable * fix_tests
1 parent ec031e1 commit 61b4999

31 files changed

+129
-126
lines changed

src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Common.targets

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,9 @@
2525
<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="Inflator" />
2626
<CompilerVisibleProperty Include="MauiXamlNoWarn" />
2727
<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="NoWarn" />
28-
<CompilerVisibleProperty Include="MauiXamlEnableDiagnostics" />
28+
<CompilerVisibleProperty Include="EnableMauiXamlDiagnostics" />
2929
<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="EnableDiagnostics" />
3030
<CompilerVisibleProperty Include="MauiXamlLineInfo" />
3131
<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="LineInfo" />
32-
<CompilerVisibleProperty Include="MauiXamlNullable" />
33-
<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="Nullable" />
3432
</ItemGroup>
3533
</Project>

src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.targets

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010
<_MauiXamlInflator Condition="' $(MauiXamlInflator)' != '' ">$(MauiXamlInflator)</_MauiXamlInflator>
1111
<_MauiXamlInflator Condition=" '$(MauiXamlInflator)' == '' And '$(Configuration)' == 'Debug' ">Runtime</_MauiXamlInflator>
1212
<_MauiXamlInflator Condition=" '$(MauiXamlInflator)' == '' And '$(Configuration)' != 'Debug' ">XamlC</_MauiXamlInflator>
13+
14+
<EnableMauiXamlDiagnostics Condition=" '$(EnableMauiXamlDiagnostics)' == '' ">$(EnableMauiDiagnostics)</EnableMauiXamlDiagnostics>
15+
<EnableMauiXamlDiagnostics Condition=" '$(EnableMauiXamlDiagnostics)' == '' And '$(Configuration)' == 'Debug' ">$(EnableDiagnostics)</EnableMauiXamlDiagnostics>
16+
<EnableMauiXamlDiagnostics Condition=" '$(EnableMauiXamlDiagnostics)' == '' And '$(Configuration)' == 'Debug' ">true</EnableMauiXamlDiagnostics>
17+
18+
<MauiXamlNoWarn Condition=" '$(MauiXamlNoWarn)' != '' ">$(MauiXamlNoWarn.Replace(';', ','))</MauiXamlNoWarn>
1319

1420
<!-- The WINUI check for this only runs when there is an empty string so I just convert false to an empty string to fall in line with our other properties -->
1521
<SkipMicrosoftUIXamlCheckTargetPlatformVersion Condition="'$(SkipMicrosoftUIXamlCheckTargetPlatformVersion)'==''">true</SkipMicrosoftUIXamlCheckTargetPlatformVersion>
@@ -83,6 +89,7 @@
8389
<!-- Assign the default inflator to MauiXaml that don't have any -->
8490
<!-- there's a roslyn bug that stops parsing value at the first semicolon. replace them all https://github.com/dotnet/roslyn/issues/43970 -->
8591
<MauiXaml Inflator="$([MSBuild]::ValueOrDefault('%(MauiXaml.Inflator)','$(_MauiXamlInflator)').Replace(';', ','))"/>
92+
<MauiXaml NoWarn="$([MSBuild]::ValueOrDefault('%(MauiXaml.NoWarn)','').Replace(';', ','))"/>
8693

8794
<_MauiXaml_SG Remove="@(_MauiXaml_SG)" />
8895
<_MauiXaml_RT Remove="@(_MauiXaml_RT)" />

src/Controls/src/SourceGen/CodeBehindCodeWriter.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,7 @@ void InitComp(string methodName, bool empty = false, bool partialsignature = fal
207207

208208
if (empty)
209209
{
210-
sb.AppendLine("#if _MAUIXAML_SG_NULLABLE_ENABLE");
211210
sb.AppendLine("#nullable enable");
212-
sb.AppendLine("#endif");
213211
}
214212

215213
sb.AppendLine();

src/Controls/src/SourceGen/CodeBehindGenerator.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ public void Initialize(IncrementalGeneratorInitializationContext initContext)
163163
context.AddSource("GlobalXmlns.g.cs", SourceText.From(
164164
$"""
165165
{AutoGeneratedHeaderText}
166+
#nullable enable
166167
167168
[assembly: global::Microsoft.Maui.Controls.XmlnsDefinition("{XamlParser.MauiGlobalUri}", "{XamlParser.MauiUri}")]
168169
[assembly: global::Microsoft.Maui.Controls.XmlnsPrefix("{XamlParser.MauiGlobalUri}", "global")]
@@ -190,6 +191,7 @@ public void Initialize(IncrementalGeneratorInitializationContext initContext)
190191

191192
var sb = new StringBuilder();
192193
sb.AppendLine(AutoGeneratedHeaderText);
194+
sb.AppendLine("#nullable enable");
193195
foreach (var xmlns in xmlnsCache.GlobalGeneratedXmlnsDefinitions)
194196
sb.AppendLine($"[assembly: global::Microsoft.Maui.Controls.XmlnsDefinition(\"{xmlns.XmlNamespace}\", \"{xmlns.Target}\", AssemblyName = \"{EscapeIdentifier(xmlns.AssemblyName)}\")]");
195197

src/Controls/src/SourceGen/Controls.SourceGen.csproj

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,7 @@
88
<NoWarn>$(NoWarn);NU5128;</NoWarn>
99
<IsRoslynComponent>true</IsRoslynComponent>
1010
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
11-
<!--
12-
_SOURCEGEN_* constants:
13-
They should be all turned on, disabling them makes it easier to read the generated code while debugging the generator.
14-
- _SOURCEGEN_LINEINFO_ENABLE: Augment the code with #line directives.
15-
- _SOURCEGEN_SOURCEINFO_ENABLE: write calls to RegisterSourceInfo (between conditions) for Instrumentation purposes
16-
-->
17-
<DefineConstants>$(DefineConstants);__SOURCEGEN__;_SOURCEGEN_LINEINFO_ENABLE;_SOURCEGEN_SOURCEINFO_ENABLE</DefineConstants>
18-
<!-- <DefineConstants>$(DefineConstants);__SOURCEGEN__</DefineConstants> -->
11+
<DefineConstants>$(DefineConstants);__SOURCEGEN__</DefineConstants>
1912
</PropertyGroup>
2013

2114
<PropertyGroup>

src/Controls/src/SourceGen/GeneratorHelpers.cs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,7 @@ static class GeneratorHelpers
2626
// Changes to this file may cause incorrect behavior and will be lost if
2727
// the code is regenerated.
2828
// </auto-generated>
29-
//------------------------------------------------------------------------------
30-
#if _MAUIXAML_SG_NULLABLE_ENABLE
31-
#nullable enable
32-
#endif
33-
";
29+
//------------------------------------------------------------------------------";
3430

3531
public static string EscapeIdentifier(string identifier)
3632
{
@@ -45,21 +41,24 @@ public static string EscapeIdentifier(string identifier)
4541
var (additionalText, optionsProvider) = tuple;
4642
var fileOptions = optionsProvider.GetOptions(additionalText);
4743
if (!fileOptions.TryGetValue("build_metadata.additionalfiles.GenKind", out string? kind) || kind is null)
48-
{
4944
return null;
50-
}
5145

5246
fileOptions.TryGetValue("build_metadata.additionalfiles.TargetPath", out var targetPath);
5347
fileOptions.TryGetValue("build_metadata.additionalfiles.ManifestResourceName", out var manifestResourceName);
5448
fileOptions.TryGetValue("build_metadata.additionalfiles.RelativePath", out var relativePath);
5549
fileOptions.TryGetValue("build_property.targetframework", out var targetFramework);
5650
fileOptions.TryGetValue("build_property.Configuration", out var configuration);
5751

58-
fileOptions.TryGetValue("build_metadata.additionalfiles.Inflator", out var inflator);
59-
52+
bool enableDiagnostics = false;
53+
if (fileOptions.TryGetValue("build_property.EnableMauiXamlDiagnostics", out var enDiag) && string.Compare(enDiag, "true", StringComparison.OrdinalIgnoreCase) == 0)
54+
enableDiagnostics = true;
55+
if (fileOptions.TryGetValue("build_property.additionalfiles.EnableDiagnostics", out enDiag) && string.Compare(enDiag, "true", StringComparison.OrdinalIgnoreCase) == 0)
56+
enableDiagnostics = true;
57+
if (fileOptions.TryGetValue("build_property.additionalfiles.EnableDiagnostics", out enDiag) && string.Compare(enDiag, "false", StringComparison.OrdinalIgnoreCase) == 0)
58+
enableDiagnostics = false;
6059

6160
var xamlinflator = 0;
62-
if (!string.IsNullOrEmpty(inflator))
61+
if (fileOptions.TryGetValue("build_metadata.additionalfiles.Inflator", out var inflator) && !string.IsNullOrEmpty(inflator))
6362
{
6463
var parts = inflator!.Split(',');
6564
for (int i = 0; i < parts.Length; i++)
@@ -71,6 +70,20 @@ public static string EscapeIdentifier(string identifier)
7170
}
7271
}
7372

73+
var enableLineInfo = true;
74+
if (fileOptions.TryGetValue("build_property.MauiXamlLineInfo", out var lineInfo) && string.Compare(lineInfo, "disable", StringComparison.OrdinalIgnoreCase) == 0)
75+
enableLineInfo = false;
76+
if (fileOptions.TryGetValue("build_metadata.additionalfiles.LineInfo", out lineInfo) && string.Compare(lineInfo, "enable", StringComparison.OrdinalIgnoreCase) == 0)
77+
enableLineInfo = true;
78+
if (fileOptions.TryGetValue("build_metadata.additionalfiles.LineInfo", out lineInfo) && string.Compare(lineInfo, "disable", StringComparison.OrdinalIgnoreCase) == 0)
79+
enableLineInfo = false;
80+
81+
string noWarn = "";
82+
if (fileOptions.TryGetValue("build_property.MauiXamlNoWarn", out var noWarnValue))
83+
noWarn = noWarnValue;
84+
if (fileOptions.TryGetValue("build_metadata.additionalfiles.NoWarn", out noWarnValue))
85+
noWarn = noWarnValue;
86+
7487
return new ProjectItem
7588
{
7689
AdditionalText = additionalText,
@@ -79,6 +92,9 @@ public static string EscapeIdentifier(string identifier)
7992
ManifestResourceName = manifestResourceName,
8093
Kind = kind,
8194
Inflator = (XamlInflator)xamlinflator,
95+
EnableLineInfo = enableLineInfo,
96+
EnableDiagnostics = enableDiagnostics,
97+
NoWarn = noWarn,
8298
TargetFramework = targetFramework,
8399
Configuration = configuration!,
84100
};
@@ -142,10 +158,7 @@ public static string EscapeIdentifier(string identifier)
142158
continue;
143159
}
144160

145-
var rootnode = new SGRootNode(new XmlType(reader.NamespaceURI, reader.Name, XamlParser.GetTypeArguments(reader)), /*typeReference, */(IXmlNamespaceResolver)reader, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition)
146-
{
147-
DisableWarnings = warningDisableList,
148-
};
161+
var rootnode = new SGRootNode(new XmlType(reader.NamespaceURI, reader.Name, XamlParser.GetTypeArguments(reader)), /*typeReference, */(IXmlNamespaceResolver)reader, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition);
149162
XamlParser.ParseXaml(rootnode, reader);
150163

151164
return rootnode;

src/Controls/src/SourceGen/InitializeComponentCodeWriter.cs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,6 @@ static class InitializeComponentCodeWriter
1616
static readonly string NewLine = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "\r\n" : "\n";
1717

1818
public static string GeneratedCodeAttribute => $"[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"{typeof(InitializeComponentCodeWriter).Assembly.FullName}\", \"{typeof(InitializeComponentCodeWriter).Assembly.GetName().Version}\")]";
19-
const string AutoGeneratedHeaderText = @"
20-
//------------------------------------------------------------------------------
21-
// <auto-generated>
22-
// This code was generated by a .NET MAUI source generator.
23-
//
24-
// Changes to this file may cause incorrect behavior and will be lost if
25-
// the code is regenerated.
26-
// </auto-generated>
27-
//------------------------------------------------------------------------------
28-
#if _MAUIXAML_SG_NULLABLE_ENABLE
29-
#nullable enable
30-
#endif
31-
";
3219

3320
public static string GenerateInitializeComponent(XamlProjectItemForIC xamlItem, Compilation compilation, SourceProductionContext sourceProductionContext, AssemblyCaches xmlnsCache, IDictionary<XmlType, ITypeSymbol> typeCache)
3421
{
@@ -37,11 +24,13 @@ public static string GenerateInitializeComponent(XamlProjectItemForIC xamlItem,
3724
PrePost newblock() =>
3825
PrePost.NewBlock(codeWriter);
3926

40-
codeWriter.WriteLine(AutoGeneratedHeaderText);
41-
var warningDisable = xamlItem.Root!.DisableWarnings != null ? string.Join(", ", xamlItem.Root!.DisableWarnings) : null;
42-
if (warningDisable != null && warningDisable.Length > 0)
27+
codeWriter.WriteLine(GeneratorHelpers.AutoGeneratedHeaderText);
28+
codeWriter.WriteLine("#nullable enable");
29+
codeWriter.WriteLine();
30+
31+
if (xamlItem.ProjectItem.NoWarn != null && xamlItem.ProjectItem.NoWarn.Length > 0)
4332
{
44-
codeWriter.WriteLine($"#pragma warning disable {warningDisable}");
33+
codeWriter.WriteLine($"#pragma warning disable {xamlItem.ProjectItem.NoWarn}");
4534
codeWriter.WriteLine();
4635
}
4736
var root = xamlItem.Root!;
@@ -97,7 +86,12 @@ PrePost newblock() =>
9786
var methodName = genSwitch ? "InitializeComponentSourceGen" : "InitializeComponent";
9887
codeWriter.WriteLine($"private partial void {methodName}()");
9988
xamlItem.Root!.XmlType.TryResolveTypeSymbol(null, compilation, xmlnsCache, out var baseType);
100-
var sgcontext = new SourceGenContext(codeWriter, compilation, sourceProductionContext, xmlnsCache, typeCache, rootType!, baseType) { FilePath = xamlItem.ProjectItem.RelativePath };
89+
var sgcontext = new SourceGenContext(codeWriter, compilation, sourceProductionContext, xmlnsCache, typeCache, rootType!, baseType)
90+
{
91+
FilePath = xamlItem.ProjectItem.RelativePath,
92+
EnableLineInfo = xamlItem.ProjectItem.EnableLineInfo,
93+
EnableDiagnostics = xamlItem.ProjectItem.EnableDiagnostics,
94+
};
10195
using (newblock())
10296
{
10397
Visit(root, sgcontext);

src/Controls/src/SourceGen/NodeSGExtensions.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -527,28 +527,28 @@ public static bool TryProvideValue(this ElementNode node, SourceGenContext conte
527527
return true;
528528
}
529529

530-
[Conditional("_SOURCEGEN_SOURCEINFO_ENABLE")]
531530
public static void RegisterSourceInfo(this INode node, SourceGenContext context, IndentedTextWriter writer, bool update = true)
532531
{
532+
if (!context.EnableDiagnostics)
533+
return;
534+
533535
if (!context.Variables.TryGetValue(node, out var variable))
534536
return;
535537

536538
var assembly = context.Compilation.Assembly.Name;
537539
var filePath = context.FilePath;
538540
var lineInfo = node as IXmlLineInfo;
539-
using (PrePost.NewConditional(writer, "_MAUIXAML_SG_SOURCEINFO"))
541+
542+
if (!update)
540543
{
541-
if (!update)
542-
{
543-
writer.WriteLine($"if (global::Microsoft.Maui.VisualDiagnostics.GetSourceInfo({variable.Name}!) == null)");
544-
writer.Indent++;
545-
}
546-
// on other inflators, we do not replace path separator, so keep the bug for compat
547-
// filePath = new UriBuilder() { Path = filePath }.Path; // ensure the file use the right separator
548-
writer.WriteLine($"global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo({variable.Name}!, new global::System.Uri(@\"{filePath};assembly={assembly}\", global::System.UriKind.Relative), {lineInfo?.LineNumber ?? -1}, {lineInfo?.LinePosition ?? -1});");
549-
if (!update)
550-
writer.Indent--;
544+
writer.WriteLine($"if (global::Microsoft.Maui.VisualDiagnostics.GetSourceInfo({variable.Name}!) == null)");
545+
writer.Indent++;
551546
}
547+
// on other inflators, we do not replace path separator, so keep the bug for compat
548+
// filePath = new UriBuilder() { Path = filePath }.Path; // ensure the file use the right separator
549+
writer.WriteLine($"global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo({variable.Name}!, new global::System.Uri(@\"{filePath};assembly={assembly}\", global::System.UriKind.Relative), {lineInfo?.LineNumber ?? -1}, {lineInfo?.LinePosition ?? -1});");
550+
if (!update)
551+
writer.Indent--;
552552
}
553553

554554
static bool IsOfAnyType(XmlType xmlType, params string[] types)

src/Controls/src/SourceGen/PrePost.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,18 @@ class PrePost : IDisposable
1616
/// <param name="fileName"></param>
1717
/// <returns></returns>
1818
public static PrePost NewLineInfo(IndentedTextWriter codeWriter, IXmlLineInfo iXmlLineInfo, string? fileName)
19-
=> new(() => LineInfo(codeWriter, iXmlLineInfo, fileName), () => LineDefault(codeWriter, iXmlLineInfo));
19+
{
20+
static void LineInfo(IndentedTextWriter codeWriter, IXmlLineInfo iXmlLineInfo, string? fileName)
21+
=> codeWriter.WriteLineNoTabs($"#line {(iXmlLineInfo.LineNumber != -1 ? iXmlLineInfo.LineNumber : 1)} \"{fileName}\"");
22+
23+
static void LineDefault(IndentedTextWriter codeWriter, IXmlLineInfo iXmlLineInfo)
24+
=> codeWriter.WriteLineNoTabs("#line default");
25+
26+
return new(() => LineInfo(codeWriter, iXmlLineInfo, fileName), () => LineDefault(codeWriter, iXmlLineInfo));
27+
}
28+
29+
public static PrePost NoBlock() =>
30+
new(() => { }, () => { });
2031

2132
public static PrePost NewConditional(IndentedTextWriter codeWriter, string condition, Action? orElse = null)
2233
{
@@ -33,6 +44,7 @@ public static PrePost NewConditional(IndentedTextWriter codeWriter, string condi
3344

3445
public static PrePost NewDisableWarning(IndentedTextWriter codeWriter, string warning)
3546
=> new(() => codeWriter.WriteLineNoTabs($"#pragma warning disable {warning}"), () => codeWriter.WriteLineNoTabs($"#pragma warning restore {warning}"));
47+
3648
readonly Action post;
3749
PrePost(Action pre, Action post)
3850
{
@@ -66,12 +78,4 @@ public static PrePost NewBlock(IndentedTextWriter codeWriter, string begin = "{"
6678
else
6779
codeWriter.WriteLine(end);
6880
});
69-
70-
[Conditional("_SOURCEGEN_LINEINFO_ENABLE")]
71-
static void LineInfo(IndentedTextWriter codeWriter, IXmlLineInfo iXmlLineInfo, string? fileName)
72-
=> codeWriter.WriteLineNoTabs($"#line {(iXmlLineInfo.LineNumber != -1 ? iXmlLineInfo.LineNumber : 1)} \"{fileName}\"");
73-
74-
[Conditional("_SOURCEGEN_LINEINFO_ENABLE")]
75-
static void LineDefault(IndentedTextWriter codeWriter, IXmlLineInfo iXmlLineInfo)
76-
=> codeWriter.WriteLineNoTabs("#line default");
7781
}

src/Controls/src/SourceGen/ProjectItem.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ record ProjectItem
1616

1717
//bypass attribute check. used for testing
1818
public string Configuration { get; internal set; } = "Debug";
19+
public bool EnableLineInfo { get; internal set; } = true;
20+
public bool EnableDiagnostics { get; internal set; } = false;
21+
public string NoWarn { get; internal set; } = "";
1922
}

0 commit comments

Comments
 (0)