Skip to content

Add x:Code directive support for inline C# in XAML#34715

Open
StephaneDelcroix wants to merge 5 commits intomainfrom
feature/xcode-support
Open

Add x:Code directive support for inline C# in XAML#34715
StephaneDelcroix wants to merge 5 commits intomainfrom
feature/xcode-support

Conversation

@StephaneDelcroix
Copy link
Copy Markdown
Contributor

@StephaneDelcroix StephaneDelcroix commented Mar 28, 2026

Description

Implements the x:Code XAML directive, allowing inline C# method definitions directly in XAML files. This complements the existing XEXPR (C# Expressions) feature.

Fixes #34712

What it does

x:Code lets you define methods inline in XAML:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.MainPage">
    <x:Code><![CDATA[
        void OnButtonClicked(object sender, EventArgs e)
        {
            // inline C# method
        }
    ]]></x:Code>
    <Button Clicked="OnButtonClicked" Text="Click me" />
</ContentPage>

Constraints

  • Requires XSG (XAML Source Generator) — not supported by Runtime inflation or XamlC
  • Requires EnablePreviewFeatures — same gate as XEXPR
  • Must be a direct child of the root element (WPF parity)
  • Must use CDATA for the code block content
  • Must have x:Class on the root element

Architecture

x:Code is implemented as a third source generator pipeline alongside CodeBehind (CB) and InitializeComponent (IC):

CB → x:Code → IC
  • ComputeXCodeSource() extracts code blocks from parsed XAML
  • XCodeCodeWriter emits a bare partial class (namespace + class + verbatim code, no usings)
  • The emitted syntax trees feed into the compilation before IC runs
  • All IC visitors skip x:Code elements via GeneratorHelpers.IsXCodeElement()

Output hint name format: {path}_{FileName}.xaml.xcode.cs

Diagnostics

ID Condition
MAUIX2012 EnablePreviewFeatures not set (reused from XEXPR)
MAUIX2015 x:Code not a direct child of root element
MAUIX2016 x:Code used without x:Class

Tests

  • 6 SourceGen unit tests — happy path, multiple blocks, no CDATA, diagnostics, no-op
  • 4 Xaml.UnitTests — SourceGen success, Runtime failure, XamlC failure, MockSourceGenerator no-diagnostics

Implements x:Code as a new source generator pipeline that extracts
inline C# code blocks from XAML and emits them as bare partial classes
(no usings). The pipeline runs between CodeBehind and InitializeComponent
generation so IC and XEXPR can resolve x:Code members.

Key changes:
- New XCodeCodeWriter for generating the partial class output
- ComputeXCodeSource extraction in GeneratorHelpers
- Pipeline wired via RegisterSourceOutput in XamlGenerator
- All IC visitors skip x:Code elements (SkipChildren + skip lists)
- XmlName.xCode added to known directives
- Diagnostics: MAUIX2015 (not child of root), MAUIX2016 (no x:Class)
- Reuses MAUIX2012 for EnablePreviewFeatures gating

Requires EnablePreviewFeatures and XAML Source Generator (XSG).

Closes #34712

Co-authored-by: Copilot <[email protected]>
Copilot AI review requested due to automatic review settings March 28, 2026 09:13
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 28, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34715

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34715"

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds x:Code support to the MAUI XAML Source Generator (XSG) so inline C# members declared in XAML can be emitted into the generated partial class, and updates SourceGen visitors/tests accordingly.

Changes:

  • Introduces an x:Code source-gen pipeline that extracts x:Code blocks and emits a .xcode.cs partial class before InitializeComponent generation.
  • Updates multiple SourceGen visitors to ignore x:Code elements during IC generation.
  • Adds new diagnostics (MAUIX2015/MAUIX2016) and unit coverage in SourceGen + Xaml.UnitTests.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/Controls/tests/Xaml.UnitTests/Issues/Maui34712.xaml.cs Adds Xaml.UnitTests coverage for SourceGen success and Runtime/XamlC unsupported behavior.
src/Controls/tests/Xaml.UnitTests/Issues/Maui34712.sgen.xaml Adds a SourceGen-only XAML repro using x:Code.
src/Controls/tests/SourceGen.UnitTests/XCodeTests.cs Adds SourceGen unit tests for x:Code output and diagnostics.
src/Controls/src/Xaml/XmlName.cs Introduces XmlName.xCode.
src/Controls/src/SourceGen/XamlGenerator.cs Wires a new incremental pipeline stage: CB → x:Code → IC.
src/Controls/src/SourceGen/XCodeCodeWriter.cs Adds a writer that emits the .xcode.cs partial class wrapper.
src/Controls/src/SourceGen/Visitors/SetResourcesVisitor.cs Skips x:Code nodes during resource visitation.
src/Controls/src/SourceGen/Visitors/SetPropertiesVisitor.cs Skips x:Code nodes during property setting and child traversal.
src/Controls/src/SourceGen/Visitors/SetNamescopesAndRegisterNames.cs Skips x:Code nodes during namescope/name registration.
src/Controls/src/SourceGen/Visitors/SetFieldsForXNamesVisitor.cs Skips x:Code nodes during x:Name field generation.
src/Controls/src/SourceGen/Visitors/ExpandMarkupsVisitor.cs Skips x:Code nodes during markup expansion.
src/Controls/src/SourceGen/Visitors/CreateValuesVisitor.cs Skips x:Code nodes during value creation.
src/Controls/src/SourceGen/TrackingNames.cs Adds tracking names for x:Code pipeline stages.
src/Controls/src/SourceGen/GeneratorHelpers.cs Adds IsXCodeElement and ComputeXCodeSource extraction logic.
src/Controls/src/SourceGen/Descriptors.cs Adds MAUIX2015/MAUIX2016 descriptors.
src/Controls/src/SourceGen/AnalyzerReleases.Unshipped.md Documents the new diagnostics.

@@ -0,0 +1,70 @@
using System;
using System.Linq;
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using System.Linq; is unused in this file. Since warnings are treated as errors in this repo, this will fail the build (CS8019). Remove the unused using.

Suggested change
using System.Linq;

Copilot uses AI. Check for mistakes.
Comment on lines +176 to +181
var (xamlItem, xmlnsCache) = input;
if (xamlItem?.Root == null || xamlItem.ProjectItem == null)
return null;

var root = xamlItem.Root;
var nsmgr = xamlItem.Nsmgr;
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xmlnsCache and nsmgr are assigned but never used. With warnings treated as errors in this repo, this will fail the build (CS0219). Use _ for the unused tuple value and remove the unused nsmgr local (or use it for namespace-aware queries).

Suggested change
var (xamlItem, xmlnsCache) = input;
if (xamlItem?.Root == null || xamlItem.ProjectItem == null)
return null;
var root = xamlItem.Root;
var nsmgr = xamlItem.Nsmgr;
var (xamlItem, _) = input;
if (xamlItem?.Root == null || xamlItem.ProjectItem == null)
return null;
var root = xamlItem.Root;

Copilot uses AI. Check for mistakes.
Comment on lines +185 to +200
// Find all x:Code child elements of the root
var codeBlocks = new List<string>();

foreach (XmlNode child in root.ChildNodes)
{
cancellationToken.ThrowIfCancellationRequested();

if (child.LocalName != "Code")
continue;
if (child.NamespaceURI != XamlParser.X2006Uri && child.NamespaceURI != XamlParser.X2009Uri)
continue;

codeBlocks.Add(child.InnerText);
}

if (codeBlocks.Count == 0)
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAUIX2015 (XCodeNotChildOfRoot) is defined, but ComputeXCodeSource currently just ignores any x:Code that isn’t an immediate root child (it won’t be extracted, and visitors will skip it), resulting in silent no-op instead of the intended diagnostic. Consider scanning the full document for x:Code elements and reporting Descriptors.XCodeNotChildOfRoot for any non-root occurrences.

Suggested change
// Find all x:Code child elements of the root
var codeBlocks = new List<string>();
foreach (XmlNode child in root.ChildNodes)
{
cancellationToken.ThrowIfCancellationRequested();
if (child.LocalName != "Code")
continue;
if (child.NamespaceURI != XamlParser.X2006Uri && child.NamespaceURI != XamlParser.X2009Uri)
continue;
codeBlocks.Add(child.InnerText);
}
if (codeBlocks.Count == 0)
// Find all x:Code elements in the document, collecting only root-level ones for generation
var codeBlocks = new List<string>();
void VisitNode(XmlNode node)
{
cancellationToken.ThrowIfCancellationRequested();
if (node.NodeType == XmlNodeType.Element &&
node.LocalName == "Code" &&
(node.NamespaceURI == XamlParser.X2006Uri || node.NamespaceURI == XamlParser.X2009Uri))
{
// x:Code must be an immediate child of the root element
if (node.ParentNode == root)
{
codeBlocks.Add(node.InnerText);
}
else if (projItem.RelativePath is string path)
{
Location location;
if (node is IXmlLineInfo lineInfo && lineInfo.HasLineInfo())
{
location = LocationHelpers.LocationCreate(path, lineInfo, node.Name);
}
else
{
location = LocationHelpers.LocationCreate(path, new XmlLineInfo(), string.Empty);
}
diagnostics.Add(Diagnostic.Create(Descriptors.XCodeNotChildOfRoot, location));
}
}
foreach (XmlNode child in node.ChildNodes)
{
VisitNode(child);
}
}
VisitNode(root);
if (codeBlocks.Count == 0 && diagnostics.Count == 0)

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

🧪 PR Test Evaluation

Overall Verdict: ⚠️ Tests need improvement

The test suite is solid for the happy path and error diagnostics, but MAUIX2015 (XCodeNotChildOfRoot) — explicitly listed in the commit message as a supported diagnostic — appears to be neither raised in the implementation nor covered by any test.

👍 / 👎 — Was this evaluation helpful? React to let us know!

📊 Expand Full Evaluation

PR Test Evaluation Report

PR: #34715 — Add x:Code directive support for inline C# in XAML
Test files evaluated: 3 (XCodeTests.cs, Maui34712.sgen.xaml, Maui34712.xaml.cs)
Fix files: 12 (SourceGen pipeline, visitors, XCodeCodeWriter, XamlGenerator, XmlName)


Overall Verdict

⚠️ Tests need improvement

Tests are well-structured and cover the main functionality, but MAUIX2015 (XCodeNotChildOfRoot) is declared, mentioned in the commit message, and tracked in AnalyzerReleases.Unshipped.md — yet it is never raised anywhere in the source code and has no test covering it. This represents either an incomplete implementation or a missing test for a real diagnostic.


1. Fix Coverage — ✅

The tests exercise the key code paths introduced by the fix:

  • XCode_GeneratesPartialClassWithMethod → exercises XCodeCodeWriter.GenerateXCode and the full pipeline in XamlGenerator for the basic case
  • XCode_MultipleBlocks_AreConcatenated → exercises ComputeXCodeSource's loop over multiple x:Code children
  • XCode_WithoutCDATA_Works → verifies raw text content extraction
  • XCode_NoXClass_ReportsDiagnostic → exercises the MAUIX2016 diagnostic path
  • XCode_WithoutPreviewFeatures_ReportsDiagnostic → exercises the MAUIX2012 gate
  • XCode_NoCodeBlocks_NoOutput → exercises the early-return path (null output)
  • XAML tests verify SourceGen inflator works end-to-end and that Runtime/XamlC inflators correctly reject x:Code

The tests would fail if the fix were reverted.


2. Edge Cases & Gaps — ⚠️

Covered:

  • Multiple x:Code blocks in the same XAML file
  • x:Code without CDATA wrapper
  • No x:Class on root element (MAUIX2016)
  • EnablePreviewFeatures not set (MAUIX2012)
  • No x:Code blocks present → no output file emitted
  • Runtime and XamlC inflators reject x:Code

Missing:

  • MAUIX2015 (x:Code not child of root) — The diagnostic is defined in Descriptors.cs and registered in AnalyzerReleases.Unshipped.md, and the commit message states "Diagnostics: MAUIX2015 (not child of root)". However, a code search finds that XCodeNotChildOfRoot/MAUIX2015 is never actually emitted anywhere in the implementation. A test for a nested x:Code (e.g. inside a StackLayout) is missing, and the implementation gap means this diagnostic would silently not fire. This should be either implemented and tested, or removed from the descriptor list.
  • Empty x:Code block — What happens with (x:Code)(![CDATA[]])(/x:Code)? An empty block would produce a partial class with no members, which may cause a compiler warning.
  • x:Code members referencing x:Name'd elements — The test XAML has a (Label x:Name="testLabel" /) alongside x:Code, but no test verifies that x:Code methods can access testLabel (the primary use case for x:Code in classic XAML). The XCodeSucceedsWithSourceGen test only calls page.GetMessage() which is self-contained.

3. Test Type Appropriateness — ✅

Current: Unit Tests (SourceGen pipeline) + XAML Tests (compile-time inflator tests)
Recommendation: Appropriate — no lighter type exists. This is entirely a source generation feature; no UI tests or device tests are needed.

The .sgen.xaml extension correctly restricts the XAML test to SourceGen-only inflation, matching the feature's scope.


4. Convention Compliance — ⚠️

Unit Tests (XCodeTests.cs): ✅ Clean — 6 [Fact] methods, descriptive names, standard xUnit patterns.

XAML Tests (Maui34712.xaml.cs):

  • ⚠️ The script flagged Maui34712.xaml as not following the MauiXXXXX pattern. This is a false positive — the actual file is Maui34712.sgen.xaml, which correctly follows MauiXXXXX.sgen.xaml convention.
  • ⚠️ The XAML test uses [Fact] / [Collection("Issue")] (xUnit) rather than [TestFixture] / [Test]([Values] XamlInflator) (NUnit). Looking at neighbouring test files (e.g. Maui34075.xaml.cs) this appears to be the project's actual convention, so this is not a defect per se. However, the tests manually specify each inflator separately (XamlInflator.SourceGen, .Runtime, .XamlC) rather than using parameterization — this is fine since x:Code explicitly only supports SourceGen.

5. Flakiness Risk — ✅ Low

Pure compiler/source-generator unit tests. No async waits, no timings, no UI, no external dependencies. These are deterministic and inherently stable.


6. Duplicate Coverage — ✅ No significant duplicates

Maui34712.xaml.cs::XCodeSourceGenProducesNoDiagnostics and XCodeTests.cs::XCode_GeneratesPartialClassWithMethod both verify the happy path produces no diagnostics, but from different angles (end-to-end XAML test vs. isolated source generator driver). Both have value.


7. Platform Scope — ✅

Source generation is a compile-time, cross-platform feature. No platform-specific code paths are involved. Unit and XAML tests running in CI without a target device cover all affected platforms correctly.


8. Assertion Quality — ✅

Generally specific and meaningful:

  • XCode_GeneratesPartialClassWithMethod checks: partial class XCodePage present, method name present, correct namespace, no using directives (explicit negative assertion for no-usings requirement)
  • XCode_MultipleBlocks_AreConcatenated checks both block contents are present in the output
  • XCodeSucceedsWithSourceGen calls Assert.Equal("Hello from x:Code", page.GetMessage()) — directly invokes the generated method, not just a null check
  • Diagnostic tests use Assert.Contains(result.Diagnostics, d => d.Id == "MAUIX2016") — specific ID check

Minor concern: XCode_NoXClass_ReportsDiagnostic doesn't assert that the count of diagnostics is exactly 1 (no extra unexpected diagnostics), but this is not critical.


9. Fix-Test Alignment — ✅

Tests map well to the changed files:

Changed Component Covered By
XCodeCodeWriter.GenerateXCode XCode_GeneratesPartialClassWithMethod, XCode_MultipleBlocks_AreConcatenated
GeneratorHelpers.ComputeXCodeSource XCode_WithoutCDATA_Works, XCode_NoXClass_ReportsDiagnostic, XCode_WithoutPreviewFeatures_ReportsDiagnostic, XCode_NoCodeBlocks_NoOutput
XamlGenerator pipeline wiring XCodeSucceedsWithSourceGen, XCodeSourceGenProducesNoDiagnostics
Visitor skip logic Indirectly covered by XCodeSourceGenProducesNoDiagnostics (IC runs without errors)
Descriptors.MAUIX2015 Not tested

Recommendations

  1. 🔴 Implement and test MAUIX2015 — Add the code to emit Descriptors.XCodeNotChildOfRoot when an x:Code element is found nested inside a non-root element, and add a test case XCode_NestedInNonRoot_ReportsDiagnostic to XCodeTests.cs that verifies d.Id == "MAUIX2015" is emitted. If this scenario intentionally silently ignores nested x:Code, remove the descriptor and the entry in AnalyzerReleases.Unshipped.md.

  2. 🟡 Add test for empty x:Code block — Verify that (x:Code)(![CDATA[]])(/x:Code) doesn't produce an empty partial class that causes compiler warnings.

  3. 🟡 Add test for x:Code members accessing x:Name'd elements — The existing test XAML already has (Label x:Name="testLabel" /) but no test calls a method that uses it. Add a method like GetLabelText() => testLabel.Text to the x:Code block and verify it's accessible, confirming the IC + x:Code pipeline interaction works end-to-end.

Warning

⚠️ Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • dc.services.visualstudio.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "dc.services.visualstudio.com"

See Network Configuration for more information.

Note

🔒 Integrity filtering filtered 1 item

Integrity filtering activated and filtered the following item during workflow execution.
This happens when a tool call accesses a resource that does not meet the required integrity or secrecy level of the workflow.

🧪 Test evaluation by Evaluate PR Tests

StephaneDelcroix and others added 2 commits March 30, 2026 09:31
Using directives (e.g. 'using System.Net.Http;') inside x:Code blocks
are now extracted and placed at the top of the generated file, outside
the namespace/class declarations. Using statements ('using var x = ...')
are correctly left inside the class body.

Duplicate using directives across multiple x:Code blocks are deduped.
Supports regular, static, and alias using directives.

Co-authored-by: Copilot <[email protected]>
- Add docs/specs/XamlXCode.md covering syntax, placement rules, using
  directive promotion, code generation pipeline, diagnostics, constraints,
  XEXPR relationship, and WPF parity notes.
- Update Maui34712 XAML test to exercise using directives inside x:Code
  (using System.Globalization for CultureInfo).

Co-authored-by: Copilot <[email protected]>
@github-actions
Copy link
Copy Markdown
Contributor

🧪 PR Test Evaluation

Overall Verdict: ⚠️ Tests need improvement

The tests are well-structured and use the right test types (SourceGen unit tests + XAML tests) for a new x:Code feature. The main gap is MAUIX2015 (XCodeNotChildOfRoot) — it is declared in Descriptors.cs and registered in AnalyzerReleases.Unshipped.md, but it is never emitted by any code in the SourceGen and has no corresponding test.

👍 / 👎 — Was this evaluation helpful? React to let us know!

📊 Expand Full Evaluation

PR Test Evaluation Report

PR: #34715 — Add x:Code directive support for inline C# in XAML
Test files evaluated: 3 (XCodeTests.cs, Maui34712.sgen.xaml, Maui34712.xaml.cs)
Fix files: 12


Overall Verdict

⚠️ Tests need improvement

Good breadth of coverage for a new feature (9 unit tests + 4 XAML tests), but MAUIX2015 is declared as a diagnostic descriptor and announced in AnalyzerReleases.Unshipped.md without being emitted by any code path, and has no test. Either the enforcement logic is missing, or the diagnostic should be removed.


1. Fix Coverage — ✅

The tests exercise the core code paths added by the fix:

  • Basic x:Code generation → XCode_GeneratesPartialClassWithMethod
  • Multiple (x:Code) blocks concatenated → XCode_MultipleBlocks_AreConcatenated
  • No-CDATA variant → XCode_WithoutCDATA_Works
  • Missing x:ClassXCode_NoXClass_ReportsDiagnostic (MAUIX2016)
  • Missing EnablePreviewFeaturesXCode_WithoutPreviewFeatures_ReportsDiagnostic (MAUIX2012)
  • No x:Code blocks → XCode_NoCodeBlocks_NoOutput
  • using directive promotion → XCode_UsingDirectives_ArePromotedToFileTop
  • Duplicate using deduplication → XCode_DuplicateUsings_AreDeduped
  • using static promotion → XCode_UsingStatic_IsPromoted
  • Runtime/XamlC throw NotSupportedExceptionXCodeFailsAtRuntime, XCodeFailsWithXamlC
  • SourceGen end-to-end with promoted usingXCodeSucceedsWithSourceGen

2. Edge Cases & Gaps — ⚠️

Covered:

  • CDATA vs plain text content
  • Multiple blocks combined
  • using dedup across blocks
  • using var stays inside class (not promoted as a directive)
  • Runtime and XamlC raise NotSupportedException

Missing:

  • MAUIX2015 not testedXCodeNotChildOfRoot is declared in Descriptors.cs and listed in AnalyzerReleases.Unshipped.md for when (x:Code) appears nested inside a child element rather than directly under the root. However, grep XCodeNotChildOfRoot src/Controls/src/SourceGen/** returns zero hits outside Descriptors.cs — the diagnostic is never emitted. Either the validation code is missing from ComputeXCodeSource/GeneratorHelpers.cs, or the descriptor should be removed.
  • using Alias = Type; not testedIsUsingDirective() in XCodeCodeWriter.cs supports alias directives but no test verifies they are promoted correctly.
  • Empty (x:Code) block — no test for (x:Code)(![CDATA[ ]])(/x:Code) (only whitespace).

3. Test Type Appropriateness — ✅

Current: SourceGen Unit Tests (XCodeTests.cs) + XAML Tests (Maui34712.xaml.cs)
Recommendation: Optimal — x:Code is purely a source-generation feature; unit/XAML tests are the lightest and most appropriate choice. No device tests or UI tests needed.


4. Convention Compliance — ✅

  • XCodeTests.cs in SourceGen.UnitTests: uses xUnit [Fact], 9 methods — ✅ follows project convention
  • Maui34712.xaml.cs in Xaml.UnitTests/Issues/: uses [Collection("Issue")] + [Fact] — ✅ consistent with existing tests in that folder (e.g., Bz41296.xaml.cs, Gh12763.xaml.cs, TestCases.cs)
  • Script warning about Maui34712.xaml not matching MauiXXXXX pattern is a false positive — the .sgen.xaml extension is what the script stumbled on; the base name Maui34712 is correct

5. Flakiness Risk — ✅ Low

Pure source-generator and in-memory compilation tests; no device, UI, or Appium involvement. No timing dependencies.


6. Duplicate Coverage — ✅ No duplicates

x:Code is a brand-new feature; no pre-existing similar tests.


7. Platform Scope — ✅

Source generation is inherently cross-platform. The tests run in-process against the Roslyn source generator, so they cover all platforms equally.


8. Assertion Quality — ✅

Assertions verify specific generated output (partial class name, namespace, method names, ordering of using directives relative to namespace), specific diagnostic IDs (MAUIX2012, MAUIX2016), and absence of diagnostics. Positional assertions (usingHttpIndex < namespaceIndex) are appropriately specific.


9. Fix-Test Alignment — ⚠️

SetPropertiesVisitor.cs was modified to skip x:Code children (SkipChildren now returns true for x:Code nodes, and the visitor bails early for x:Code elements). There is no explicit test verifying that existing XAML features still work correctly when (x:Code) appears alongside other elements (e.g., (Label) with bindings or x:Name). The existing XCode_GeneratesPartialClassWithMethod includes a (Label Text="Test" /) sibling, but doesn't assert on the IC (InitializeComponent) output for that sibling.


Recommendations

  1. Fix or remove MAUIX2015 — Either add the validation logic in ComputeXCodeSource (or a dedicated visitor) to emit XCodeNotChildOfRoot when (x:Code) is nested, and add a corresponding test; or remove the descriptor and its AnalyzerReleases.Unshipped.md entry if the constraint won't be enforced.
  2. Add a test for using Alias = Type; — Alias directives are supported by IsUsingDirective() but unverified. A small addition to XCodeTests.cs would suffice.
  3. Add a sibling-element IC test — A test that uses x:Code alongside a named element (e.g., (Label x:Name="myLabel")) and asserts that the InitializeComponent output still correctly wires up myLabel would confirm the visitor bypass doesn't accidentally break IC generation.

Warning

⚠️ Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • dc.services.visualstudio.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "dc.services.visualstudio.com"

See Network Configuration for more information.

Note

🔒 Integrity filtering filtered 1 item

Integrity filtering activated and filtered the following item during workflow execution.
This happens when a tool call accesses a resource that does not meet the required integrity or secrecy level of the workflow.

🧪 Test evaluation by Evaluate PR Tests

Comment on lines +228 to +229
if (rootType == null || rootClrNamespace == null)
return null;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No diagnostic in this case? I think this should either never be possible (and throw), or this deserves a diagnostic.

Comment on lines +354 to +355
if (GeneratorHelpers.IsXCodeElement(node))
return;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes me wonder, should we add CodeElement and have a visitor that identifies and converts the x:Code elements into this element? that way we wouldn't need to have all those annoying SkipChildren changes + it would communicate the intent much better.

sourceProductionContext.ReportDiagnostic(diag);

if (!string.IsNullOrEmpty(xcode.Source))
sourceProductionContext.AddSource(GetHintName(xcode.ProjectItem, "xcode"), xcode.Source);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if there are multiple x:Code blocks in one XAML item? If I understand the code, we're not merging them into one big xcode, are we? I suppose there's nothing stopping the devs to do it and while I suppose the "hint name" is really just a hint and hopefully roslyn can handle de-duplication, let's add at least 1 test that covers this (that this doesn't produce a warning/error or that we don't overwrite the first xcode block).

Comment on lines +69 to +75
<x:Code><![CDATA[
int _count;
]]></x:Code>
<Label Text="Test" />
<x:Code><![CDATA[
void Increment() => _count++;
]]></x:Code>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, so I was wrong in an earlier comment, we are merging all the x:Code elements into a single partial class body.

1. Emit MAUIX2016 when x:Class is present but malformed (ParseXmlns
   returns null), instead of silently returning null.

2. Strip x:Code elements from the node tree in
   InitializeComponentCodeWriter before IC visitors run. This replaces
   the scattered IsXCodeElement checks in 6 visitors with a single
   StripXCodeElements call, making the intent clearer and keeping
   visitor code clean.

3. Multiple x:Code blocks are already  covered by the existingmerged
   XCode_MultipleBlocks_AreConcatenated test.

Co-authored-by: Copilot <[email protected]>
@github-actions
Copy link
Copy Markdown
Contributor

🧪 PR Test Evaluation

Overall Verdict: ⚠️ Tests need improvement

Tests are well-structured and cover the happy path thoroughly, but there is a notable gap: the newly defined diagnostic MAUIX2015 (XCodeNotChildOfRoot) is registered and documented but never emitted by the implementation — and has no test.

👍 / 👎 — Was this evaluation helpful? React to let us know!

📊 Expand Full Evaluation

PR Test Evaluation Report

PR: #34715x:Code directive support for inline C# in XAML (SourceGen)
Test files evaluated: 3 (XCodeTests.cs, Maui34712.sgen.xaml, Maui34712.xaml.cs)
Fix files: 8 (SourceGen pipeline, XCodeCodeWriter.cs, GeneratorHelpers.cs, SetPropertiesVisitor.cs, InitializeComponentCodeWriter.cs, Descriptors.cs, TrackingNames.cs, XmlName.cs)


Overall Verdict

⚠️ Tests need improvement

The test suite is solid for the happy path (SourceGen code generation) and covers several important edge cases (no CDATA, multiple blocks, using directive promotion, duplicate deduplication, diagnostics). However, MAUIX2015 (XCodeNotChildOfRoot) is defined in Descriptors.cs and added to AnalyzerReleases.Unshipped.md but the implementation never emits it — and there is no test for it.


1. Fix Coverage — ✅

The XCodeTests.cs tests directly exercise XCodeCodeWriter.GenerateXCode and GeneratorHelpers.ComputeXCodeSource through the source generator pipeline. The Maui34712.xaml.cs tests additionally exercise the full XamlInflator lifecycle (SourceGen succeeds, Runtime/XamlC throw NotSupportedException). Coverage of the core feature is good.

2. Edge Cases & Gaps — ⚠️

Covered:

  • x:Code without x:ClassMAUIX2016 diagnostic emitted ✅
  • x:Code without EnablePreviewFeaturesMAUIX2012 diagnostic emitted ✅
  • Multiple x:Code blocks → concatenated into single partial class ✅
  • x:Code without CDATA wrapper ✅
  • No x:Code elements → no output file generated ✅
  • using directives extracted and promoted before namespace ✅
  • Duplicate using directives deduplicated ✅
  • using static promoted ✅
  • Runtime and XamlC inflation throws NotSupportedException
  • Full SourceGen round-trip via Maui34712.sgen.xaml — methods callable from C# ✅

Missing:

  • MAUIX2015 (XCodeNotChildOfRoot) is dead code: The diagnostic is defined in Descriptors.cs and listed in AnalyzerReleases.Unshipped.md, but nowhere in the implementation is it ever emitted. StripXCodeElements only removes direct root children, ComputeXCodeSource only iterates root.ChildNodes, and SetPropertiesVisitor.skips just silently ignores x:Code anywhere. There is no code path that detects a nested x:Code and reports MAUIX2015. Either the diagnostic should be removed, or the implementation and a test for it should be added.
  • Using alias (using X = Namespace.Type;): Not tested. The IsUsingDirective method would accept this form, but there's no test to confirm it's promoted correctly to the file top.
  • Empty x:Code block: Not tested — what happens when (x:Code)(/x:Code) contains only whitespace?

3. Test Type Appropriateness — ✅

Current: Unit Tests (XCodeTests.cs in SourceGen.UnitTests) + XAML Tests (Maui34712.sgen.xaml / Maui34712.xaml.cs)

Both are the lightest possible test types for this feature. Source generation is a compile-time step — there is no need for device tests or UI tests. Optimal choice.

4. Convention Compliance — ⚠️

  • Maui34712.sgen.xaml: The script flagged the file name, but this is a false positive.sgen.xaml is a recognized extension in the project (handled via MauiXaml Update="**\*.sgen.xaml" Inflator="SourceGen" in the .csproj), and the issue-number naming Maui34712 is correct.
  • Maui34712.xaml.cs uses separate [Fact] methods per inflator instead of the conventional [Theory] + [XamlInflatorData] pattern. This is acceptable given that x:Code behaves differently per inflator (SourceGen succeeds; Runtime/XamlC throw), but using a combined theory with if (inflator == XamlInflator.SourceGen) branches is the established pattern in the project and would be more consistent.
  • The [Collection("Issue")] class attribute is correct for XAML unit tests.
  • XCodeTests.cs follows [Fact] / xUnit conventions cleanly. ✅

5. Flakiness Risk — ✅ Low

All tests are pure source generation / compilation tests. No async timing, no Appium, no device I/O, no screenshots. Very low flakiness risk.

6. Duplicate Coverage — ✅ No duplicates

This is an entirely new feature (x:Code support). No existing tests cover this scenario.

7. Platform Scope — ✅

x:Code is a XAML source generation feature that runs at compile time and is cross-platform. Unit and XAML tests run on all platforms. No platform-specific gap.

8. Assertion Quality — ✅

Assertions are specific and meaningful:

  • Assert.Contains("partial class XCodePage", xcode) — proves the generated file is a partial class in the right type
  • Assert.True(usingHttpIndex < namespaceIndex) — verifies positional placement of promoted usings
  • Assert.Equal(1, count) — verifies deduplication produces exactly one instance
  • Assert.Contains(result.Diagnostics, d => d.Id == "MAUIX2016") — verifies the exact diagnostic ID
  • page.GetMessage() / page.GetFormattedDate() — calls real generated methods, not just checking non-null

No meaningless assertions (Assert.That(true)) or magic-number brittleness observed.

9. Fix-Test Alignment — ✅

All test scenarios map directly to the changed code:

  • XCodeCodeWriter.GenerateXCode → tested by XCode_GeneratesPartialClassWithMethod, XCode_UsingDirectives_ArePromotedToFileTop, XCode_DuplicateUsings_AreDeduped, XCode_UsingStatic_IsPromoted
  • GeneratorHelpers.ComputeXCodeSource (no x:Class gate) → tested by XCode_NoXClass_ReportsDiagnostic
  • GeneratorHelpers.ComputeXCodeSource (EnablePreviewFeatures gate) → tested by XCode_WithoutPreviewFeatures_ReportsDiagnostic
  • SetPropertiesVisitor.skips + StripXCodeElements → implicitly covered by XCodeSucceedsWithSourceGen (no "unexpected node" error)

Recommendations

  1. [Required] Remove or implement MAUIX2015 / XCodeNotChildOfRoot: This diagnostic is defined and documented but never emitted. Either add the implementation (detect nested x:Code elements and report the diagnostic) along with a test — or remove the descriptor and its AnalyzerReleases.Unshipped.md entry. Shipping a documented-but-dead diagnostic would confuse users.

  2. [Minor] Add a test for using alias promotion: using HttpAlias = System.Net.Http.HttpClient; should verify the alias form is correctly promoted to the file top.

  3. [Minor] Consider using [Theory] + [XamlInflatorData] in Maui34712.xaml.cs: The current [Fact] per inflator is readable, but using the established project convention with a single theory and per-inflator branching would improve consistency.

Warning

⚠️ Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • dc.services.visualstudio.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "dc.services.visualstudio.com"

See Network Configuration for more information.

Note

🔒 Integrity filtering filtered 1 item

Integrity filtering activated and filtered the following item during workflow execution.
This happens when a tool call accesses a resource that does not meet the required integrity or secrecy level of the workflow.

🧪 Test evaluation by Evaluate PR Tests

simonrozsival
simonrozsival previously approved these changes Mar 30, 2026
The generated .xcode.cs file is a separate compilation unit and needs
its own 'using System' to resolve DateTime.

Co-authored-by: Copilot <[email protected]>
@github-actions
Copy link
Copy Markdown
Contributor

🧪 PR Test Evaluation

Overall Verdict: ✅ Tests are adequate

The PR adds x:Code support to the XAML Source Generator with 9 focused unit tests and XAML integration tests — the right test types for this feature, with good assertion quality and no flakiness risk.

👍 / 👎 — Was this evaluation helpful? React to let us know!

📊 Expand Full Evaluation

PR Test Evaluation Report

PR: #34715 — x:Code support for XAML Source Generator
Test files evaluated: 3 (XCodeTests.cs, Maui34712.sgen.xaml, Maui34712.xaml.cs)
Fix files: 8 (SourceGen pipeline files + XmlName.cs)


Overall Verdict

✅ Tests are adequate

9 unit tests directly exercise the new XCodeCodeWriter and source generator pipeline, supplemented by XAML integration tests. The correct test types were chosen for a purely compile-time feature, and the assertions are specific enough to catch regressions.


1. Fix Coverage — ✅

The unit tests in XCodeTests.cs are tightly coupled to the implementation:

  • XCode_GeneratesPartialClassWithMethod → exercises XCodeCodeWriter.GenerateXCode and verifies the generated partial class structure
  • XCode_MultipleBlocks_AreConcatenated → exercises the multi-block aggregation path in XamlGenerator
  • XCode_UsingDirectives_ArePromotedToFileTop / XCode_DuplicateUsings_AreDeduped / XCode_UsingStatic_IsPromoted → exercises IsUsingDirective + the using-promotion logic
  • XCode_NoXClass_ReportsDiagnostic / XCode_WithoutPreviewFeatures_ReportsDiagnostic → exercises the MAUIX2016 and MAUIX2012 diagnostic paths in Descriptors.cs
  • XCode_NoCodeBlocks_NoOutput → verifies the generator produces no .xcode.cs source when no x:Code is present

Maui34712.xaml.cs adds integration-level verification that the feature works end-to-end (including the GetMessage() / GetFormattedDate() methods from the XAML file), and explicitly confirms NotSupportedException for Runtime and XamlC inflators.

All significant code paths in the new files have test coverage that would fail if the fix were reverted.


2. Edge Cases & Gaps — ⚠️

Covered:

  • Basic code generation (partial class, namespace, method)
  • Multiple x:Code blocks concatenated
  • CDATA vs. non-CDATA content
  • Missing x:Class → MAUIX2016 diagnostic
  • Missing preview features → MAUIX2012 diagnostic
  • No x:Code blocks → no output file
  • using directive promotion to file top
  • Duplicate using deduplication
  • using static promotion
  • using var / using (...) correctly classified as statements (not promoted)
  • Runtime and XamlC inflators throw NotSupportedException

Missing / potential gaps:

  • Using alias (using Alias = System.Type;): IsUsingDirective should handle this (it ends with ; and doesn't start with var or (), but no test covers it explicitly
  • Empty or whitespace-only x:Code block ((x:Code)(/x:Code)): no test for this boundary — does it produce an empty partial class or is it silently skipped?
  • C# syntax errors inside x:Code: the generator feeds the x:Code source into a CSharpSyntaxTree — no test verifies what diagnostics (if any) are emitted when the inline code is syntactically invalid
  • x:Code inside a non-page root (e.g., inside a DataTemplate or nested control): only tested at root ContentPage level

3. Test Type Appropriateness — ✅

Current: Unit Tests (SourceGen) + XAML Unit Tests
Recommendation: This is the optimal choice — no lighter type is applicable.

x:Code is a purely compile-time source generator feature with no runtime rendering or platform interaction. Unit tests via the generator driver are the fastest and most precise way to verify it. No UI tests or device tests are needed or appropriate.


4. Convention Compliance — ✅

The XAML unit test project (Xaml.UnitTests) uses xUnit (not NUnit), with [Collection("Issue")] + [Theory]/[XamlInflatorData] or [Fact]. Maui34712.xaml.cs follows this project-level convention correctly.

Using explicit [Fact] tests for each inflator case (rather than [Theory]/[XamlInflatorData]) is intentional and appropriate here: x:Code only supports SourceGen, so the test needs to assert NotSupportedException for Runtime/XamlC rather than success — that would be awkward to express with [XamlInflatorData].

Script-flagged issue: The script warned that Maui34712.xaml "doesn't follow MauiXXXXX pattern" — this is a false positive. The file is Maui34712.sgen.xaml and the script's regex did not account for the .sgen. suffix.

Note: Maui34712.xaml.cs has 0 test methods detected by the script because it uses [Fact] instead of [Theory]/[XamlInflatorData] — another false positive in the automated check.


5. Flakiness Risk — ✅ Low

All tests are synchronous unit tests against an in-memory source generator — no Appium, no device, no timing dependencies, no screenshots, no async waiting. Flakiness risk is effectively zero.


6. Duplicate Coverage — ✅ No duplicates

x:Code is a new feature; no similar tests exist in the codebase.


7. Platform Scope — ✅

The source generator runs as a pure .NET Roslyn analyzer; tests run on all platforms in CI without platform-specific paths. Coverage is inherently cross-platform.


8. Assertion Quality — ✅

Assertions are specific and targeted:

  • Diagnostic ID checks (d.Id == "MAUIX2016") rather than just "a diagnostic was emitted"
  • Index-based ordering checks (usingHttpIndex < namespaceIndex) for the using-promotion tests
  • Exact count assertions (Assert.Equal(1, count)) for deduplication
  • Functional assertions (Assert.Equal("Hello from x:Code", page.GetMessage())) in the XAML integration test

Minor concern: the DoesNotContain("using ", nonCommentLines) check in XCode_GeneratesPartialClassWithMethod only strips // single-line comments before checking — /* */ block comments with using in them would produce a false positive, though this is low-probability.


9. Fix-Test Alignment — ✅

All test scenarios map directly to the changed files:

  • XCodeCodeWriter.cs → tested by all XCode_* unit tests
  • Descriptors.cs (MAUIX2016, MAUIX2012) → tested by XCode_NoXClass_ReportsDiagnostic and XCode_WithoutPreviewFeatures_ReportsDiagnostic
  • XamlGenerator.cs (pipeline) → integration-tested by Maui34712.xaml.cs
  • XmlName.xCode constant → used implicitly by all XAML parsing tests

Recommendations

  1. Add a test for using aliases — add a [Fact] for using Alias = System.Type; to confirm IsUsingDirective correctly classifies it as a directive (promoted) rather than a statement
  2. Test empty / whitespace-only x:Code blocks — verify the generator handles (x:Code)(/x:Code) gracefully (either silently skips or produces a valid empty partial class)
  3. Test x:Code with C# syntax errors — verify the generator emits a useful diagnostic (or at least doesn't crash) when the inline code content is syntactically invalid

Warning

⚠️ Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • dc.services.visualstudio.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "dc.services.visualstudio.com"

See Network Configuration for more information.

Note

🔒 Integrity filtering filtered 1 item

Integrity filtering activated and filtered the following item during workflow execution.
This happens when a tool call accesses a resource that does not meet the required integrity or secrecy level of the workflow.

🧪 Test evaluation by Evaluate PR Tests

@StephaneDelcroix
Copy link
Copy Markdown
Contributor Author

/azp run maui-pr-uitests, maui-pr-devicetests

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 2 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Support x:Code directive for inline C# in XAML

3 participants