Repository navigation
Conversation
Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 38651Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 38651" |
|
Hey there @@Shalini-Ashokan! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
|
Azure Pipelines: Successfully started running 1 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
This comment has been minimized.
This comment has been minimized.
|
Warning Your |
This comment has been minimized.
This comment has been minimized.
|
Note 🔍
|
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines: Successfully started running 2 pipeline(s). |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Note 🔍
|
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@Shalini-Ashokan — new AI review results are available based on commit
6b4b1f9.
🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix
Gate Result: ✅ PASSED
Platform: ANDROID · Base: main · Merge base: f8a2f062
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🧪 IntegrationTests IntegrationTests |
✅ FAIL — 139s | ✅ PASS — 124s |
🔴 Without fix — 🧪 IntegrationTests: FAIL ✅ · 139s
Error-relevant lines (filtered from the build log):
at BindingSourceGen.UnitTests.IntegrationTests.GenerateBindingForNullConditionalTarget() in /_/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs:line 168
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
🟢 With fix — 🧪 IntegrationTests: PASS ✅ · 124s
(no coded error found; showing last 1200 chars)
egrationTests.GenerateBindingWithForcedConditionalAccessAfterCast [252 ms]
Passed BindingSourceGen.UnitTests.IntegrationTests.IgnoresOtherOtherCreateMethod [141 ms]
Passed BindingSourceGen.UnitTests.IntegrationTests.GenerateBindingForNullConditionalTarget [179 ms]
Passed BindingSourceGen.UnitTests.IntegrationTests.IgnoresOtherBindingCreateMethod [452 ms]
Passed BindingSourceGen.UnitTests.IntegrationTests.GenerateSimpleBinding_WithInitSetter [346 ms]
Passed BindingSourceGen.UnitTests.IntegrationTests.GeneratedMethodNameUsesStableLocationId [295 ms]
Passed BindingSourceGen.UnitTests.IntegrationTests.GenerateSimpleBindingWhenNullableDisabledNonNullableValueType [191 ms]
Passed BindingSourceGen.UnitTests.IntegrationTests.GenerateBindingWithPrivateReadonlyProperty [198 ms]
[xUnit.net 00:00:13.49] Finished: Controls.BindingSourceGen.UnitTests
Passed BindingSourceGen.UnitTests.IntegrationTests.GenerateBindingWithNullableObjectAndNullableReferenceTypeProperty_SetBinding [218 ms]
Passed BindingSourceGen.UnitTests.IntegrationTests.GenerateBindingWithNonNullableReferenceTypesCasts [174 ms]
Test Run Successful.
Total tests: 33
Passed: 33
Total time: 14.7863 Seconds
📁 Fix files reverted (2 files)
src/Controls/src/BindingSourceGen/BindingSourceGenerator.cssrc/Controls/src/BindingSourceGen/InvocationParser.cs
📋 Pre-Flight — Context & Validation
PR #38651 Pre-Flight
Scope
- PR:
Fix compiled binding generation for null-conditional SetBinding calls - Issue: #38365,
Compiled-binding interceptor not generated for SetBinding call wrapped in null-conditional access (?.) - Base / platform:
main/ Android - Review branch / commit:
pr-review-38651/962069a8f5e77adb83c623d67430b70c1bc15979 - Gate: Passed previously. The
IntegrationTestsclass fails without the PR fix and passes with it; this phase must not repeat gate verification.
Problem
An eligible compiled-binding call such as label?.SetBinding(...) is represented by Roslyn as an invocation whose expression is a MemberBindingExpressionSyntax, rather than the MemberAccessExpressionSyntax used by label.SetBinding(...). The generator's syntax predicate therefore skips the null-conditional call, emits no interceptor, and the application later throws InvalidOperationException when the generic SetBinding call executes.
Current PR Approach
The PR changes 3 files (+36/-5):
BindingSourceGenerator.csaddsGetInvokedMethodName(ExpressionSyntax), mapping bothMemberAccessExpressionSyntaxandMemberBindingExpressionSyntaxto theirSimpleNameSyntax. The helper is used by the syntax predicate and source-location extraction.InvocationParser.csuses that same helper instead of directly casting the invocation expression toMemberAccessExpressionSyntax.IntegrationTests.csaddsGenerateBindingForNullConditionalTarget, asserting clean diagnostics, a generated binding, and an interceptable location.
This approach is a shared syntax-shape abstraction. Alternatives must not merely rename or relocate the same helper; they need a different mechanism-level strategy.
Allowed Production Files
EstablishBrokenBaseline.ps1 previously detected these two revertable fix files:
src/Controls/src/BindingSourceGen/BindingSourceGenerator.cssrc/Controls/src/BindingSourceGen/InvocationParser.cs
The test file is retained at the PR version and is read-only during try-fix attempts. Each attempt must honor .github/.baseline-state.json after establishing its baseline.
Bounded Validation
Run only the primary regression and its mandatory neighboring regression slice:
dotnet test src/Controls/tests/BindingSourceGen.UnitTests/Controls.BindingSourceGen.UnitTests.csproj --filter "FullyQualifiedName~BindingSourceGen.UnitTests.IntegrationTests"This executes the 33 IntegrationTests, including GenerateBindingForNullConditionalTarget; it is not the full project suite. Each candidate is limited to one implementation/test pass and at most one focused correction/retest.
Constraints
- At most two candidates, sequentially:
gpt-5.3-codex, thengpt-5.6-sol. - Each child invokes the
try-fixskill exactly once and performs its inline expert self-review; no additional reviewer agents. - Preserve all attempt artifacts and always restore through
pwsh .github/scripts/EstablishBrokenBaseline.ps1 -Restore. - Do not modify or overwrite
PRAgent/gate/content.md.
🔬 Code Review — Deep Analysis
Expert Evaluation — PR #38651
Verdict: NEEDS_DISCUSSION
Confidence: low
Independent Assessment
The submitted change correctly recognizes both ordinary member access (label.SetBinding(...)) and conditional member binding (label?.SetBinding(...)) through a shared GetInvokedMethodName(ExpressionSyntax) helper. Reusing that helper in syntax filtering, source-location extraction, and invocation parsing keeps the Roslyn syntax-shape handling consistent and avoids the unsafe direct casts that previously excluded the null-conditional form.
The approach is narrow and sound:
- Null-conditional
SetBindingcalls now reach semantic verification and interceptor generation. - Existing direct
SetBindingbehavior is preserved. Binding.Createcandidate filtering remains unchanged, while parser dispatch continues to recognize it.- Unsupported expression shapes now produce the existing
UnableToResolvePathdiagnostic path rather than failing through an invalid cast. - The new regression test covers clean diagnostics, generated binding presence, and an interceptable location.
Findings
No actionable code-level defects were found. The required inline findings artifact contains an empty JSON array.
The reviewer identified one non-blocking test-strengthening opportunity: assert a stable property of the generated interceptor output rather than only its presence. This can improve regression precision if it can be expressed using existing test conventions without coupling the test to incidental generated formatting.
CI and Gate Evidence
The expert reviewer could not independently observe required GitHub checks and therefore conservatively returned NEEDS_DISCUSSION with low confidence. The trusted workflow Gate supplied to this comparison is stronger task-specific evidence: the focused regression fails without the submitted fix and passes with it. Per the execution contract, that Gate is accepted and is not rerun.
Refinement Recommendation
Consider one consolidated pr-plus-reviewer refinement limited to strengthening the new regression test. Do not alter the production fix unless the focused inspection identifies a concrete issue.
🛠️ Try-Fix — Analysis & Comparison
STEP 5a Try-Fix Aggregate
Candidate 1 — Inline Syntax-Shape Matching
Model: gpt-5.3-codex
Approach: Recognize MemberAccessExpressionSyntax and MemberBindingExpressionSyntax through local switch patterns at each affected consumption site: the IsSetBindingMethod predicate, source-location extraction in GetBindingForGeneration, and dispatch in InvocationParser.ParseInvocation.
Difference from the PR: The PR centralizes method-name extraction in a shared GetInvokedMethodName(ExpressionSyntax) helper. Candidate 1 deliberately avoids that abstraction and performs local shape-specific matching independently at each site. It fixes the same AST mismatch through duplicated local patterns rather than shared extraction.
Files changed:
src/Controls/src/BindingSourceGen/BindingSourceGenerator.cssrc/Controls/src/BindingSourceGen/InvocationParser.cs
Captured diff:
diff --git a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs
index 083df614a4..99832565ee 100644
--- a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs
+++ b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs
@@ -92,8 +92,12 @@ public class BindingSourceGenerator : IIncrementalGenerator
private static bool IsSetBindingMethod(SyntaxNode node)
{
return node is InvocationExpressionSyntax invocation
- && invocation.Expression is MemberAccessExpressionSyntax method
- && method.Name.Identifier.Text == "SetBinding"
+ && invocation.Expression switch
+ {
+ MemberAccessExpressionSyntax memberAccess => memberAccess.Name.Identifier.Text == "SetBinding",
+ MemberBindingExpressionSyntax memberBinding => memberBinding.Name.Identifier.Text == "SetBinding",
+ _ => false
+ }
&& invocation.ArgumentList.Arguments.Count >= 2
&& invocation.ArgumentList.Arguments[1].Expression is not LiteralExpressionSyntax
&& invocation.ArgumentList.Arguments[1].Expression is not ObjectCreationExpressionSyntax;
@@ -137,7 +141,16 @@ public class BindingSourceGenerator : IIncrementalGenerator
var enabledNullable = IsNullableContextEnabled(context);
var invocation = (InvocationExpressionSyntax)context.Node;
- var method = (MemberAccessExpressionSyntax)invocation.Expression;
+ var methodName = invocation.Expression switch
+ {
+ MemberAccessExpressionSyntax memberAccess => memberAccess.Name,
+ MemberBindingExpressionSyntax memberBinding => memberBinding.Name,
+ _ => null
+ };
+ if (methodName is null)
+ {
+ return Result<BindingInvocationDescription>.Failure(DiagnosticsFactory.UnableToResolvePath(invocation.GetLocation()));
+ }
var invocationParser = new InvocationParser(context);
var interceptedMethodTypeResult = invocationParser.ParseInvocation(invocation, t);
@@ -151,7 +164,7 @@ public class BindingSourceGenerator : IIncrementalGenerator
var interceptableLocation = context.SemanticModel.GetInterceptableLocation(invocation, t);
#pragma warning restore RSEXPERIMENTAL002
- var sourceCodeLocation = SourceCodeLocation.CreateFrom(method.Name.GetLocation());
+ var sourceCodeLocation = SourceCodeLocation.CreateFrom(methodName.GetLocation());
diff --git a/src/Controls/src/BindingSourceGen/InvocationParser.cs b/src/Controls/src/BindingSourceGen/InvocationParser.cs
index 006103c280..c26dcfd1d5 100644
--- a/src/Controls/src/BindingSourceGen/InvocationParser.cs
+++ b/src/Controls/src/BindingSourceGen/InvocationParser.cs
@@ -20,10 +20,14 @@ internal class InvocationParser
internal Result<InterceptedMethodType> ParseInvocation(InvocationExpressionSyntax invocationSyntax, CancellationToken t)
{
- return ((MemberAccessExpressionSyntax)invocationSyntax.Expression).Name.Identifier.Text switch
+ return invocationSyntax.Expression switch
{
- InterceptedMethodsNames.SetBinding => VerifyCorrectOverloadSetBinding(invocationSyntax, t),
- InterceptedMethodsNames.Create => VerifyCorrectOverloadBindingCreate(invocationSyntax, t),
+ MemberAccessExpressionSyntax { Name.Identifier.Text: InterceptedMethodsNames.SetBinding }
+ or MemberBindingExpressionSyntax { Name.Identifier.Text: InterceptedMethodsNames.SetBinding }
+ => VerifyCorrectOverloadSetBinding(invocationSyntax, t),
+ MemberAccessExpressionSyntax { Name.Identifier.Text: InterceptedMethodsNames.Create }
+ or MemberBindingExpressionSyntax { Name.Identifier.Text: InterceptedMethodsNames.Create }
+ => VerifyCorrectOverloadBindingCreate(invocationSyntax, t),
_ => throw new NotSupportedException()
};
}Test command:
dotnet test src/Controls/tests/BindingSourceGen.UnitTests/Controls.BindingSourceGen.UnitTests.csproj --filter "FullyQualifiedName~BindingSourceGen.UnitTests.IntegrationTests"Test result: Pass on the first and only execution: 33 passed, 0 failed, 0 skipped.
Inline self-review: Clean, 0 findings (reviewer-findings.json contains []).
Analysis: Local handling of both Roslyn invocation shapes admits the null-conditional call into generation, obtains the method-name location, and dispatches it as SetBinding, so the retained regression receives an interceptor. The candidate is functional but repeats the same shape mapping three times, whereas the PR keeps that knowledge in one helper.
Artifacts: CustomAgentLogsTmp/PRState/38651/PRAgent/try-fix/attempt-1/
Restoration: EstablishBrokenBaseline.ps1 -Restore completed with Restored True; .github/.baseline-state.json was cleared.
Candidate 2 — Select the Method Name as the Syntax Candidate
Model: gpt-5.6-sol
Approach: Change the incremental syntax provider's selection unit from the enclosing InvocationExpressionSyntax to the invoked SimpleNameSyntax (SetBinding or Create). Both direct and null-conditional calls expose the same method-name child node. The transform walks from that selected name to its invocation, passes the selected node to InvocationParser, and uses it directly for source location. A terminal-span check prevents a receiver named SetBinding from being mistaken for the invoked method.
Difference from the PR and Candidate 1: The PR extracts a name from either of two enclosing expression shapes through a shared helper. Candidate 1 performs the same two-shape mapping locally at three sites. Candidate 2 does not map enclosing shapes at all: it selects the common child name directly, so predicate selection, dispatch, and location all begin with the stable node needed by the generator. Its mechanism is selection rather than extraction.
Files changed:
src/Controls/src/BindingSourceGen/BindingSourceGenerator.cssrc/Controls/src/BindingSourceGen/InvocationParser.cs
Captured diff:
diff --git a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs
index 083df614a4..b1ab510716 100644
--- a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs
+++ b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs
@@ -91,9 +91,9 @@ public class BindingSourceGenerator : IIncrementalGenerator
private static bool IsSetBindingMethod(SyntaxNode node)
{
- return node is InvocationExpressionSyntax invocation
- && invocation.Expression is MemberAccessExpressionSyntax method
- && method.Name.Identifier.Text == "SetBinding"
+ return node is SimpleNameSyntax { Identifier.Text: "SetBinding" } method
+ && method.Parent?.Parent is InvocationExpressionSyntax invocation
+ && method.Span.End == invocation.Expression.Span.End
&& invocation.ArgumentList.Arguments.Count >= 2
&& invocation.ArgumentList.Arguments[1].Expression is not LiteralExpressionSyntax
&& invocation.ArgumentList.Arguments[1].Expression is not ObjectCreationExpressionSyntax;
@@ -101,13 +101,13 @@ public class BindingSourceGenerator : IIncrementalGenerator
private static bool IsCreateMethod(SyntaxNode node)
{
- return node is InvocationExpressionSyntax invocation
- && invocation.Expression is MemberAccessExpressionSyntax method
- && method.Name.Identifier.Text == "Create"
+ return node is SimpleNameSyntax { Identifier.Text: "Create" } method
+ && method.Parent is MemberAccessExpressionSyntax memberAccess
+ && memberAccess.Parent is InvocationExpressionSyntax invocation
&& invocation.ArgumentList.Arguments.Count >= 1
&& invocation.ArgumentList.Arguments[0].Expression is not LiteralExpressionSyntax
&& invocation.ArgumentList.Arguments[0].Expression is not ObjectCreationExpressionSyntax
- && GetTypeNameFromExpression(method.Expression) switch
+ && GetTypeNameFromExpression(memberAccess.Expression) switch
{
"Binding" => true,
"BindingBase" => true,
@@ -136,11 +136,11 @@ public class BindingSourceGenerator : IIncrementalGenerator
{
var enabledNullable = IsNullableContextEnabled(context);
- var invocation = (InvocationExpressionSyntax)context.Node;
- var method = (MemberAccessExpressionSyntax)invocation.Expression;
+ var method = (SimpleNameSyntax)context.Node;
+ var invocation = (InvocationExpressionSyntax)method.Parent!.Parent!;
var invocationParser = new InvocationParser(context);
- var interceptedMethodTypeResult = invocationParser.ParseInvocation(invocation, t);
+ var interceptedMethodTypeResult = invocationParser.ParseInvocation(invocation, method, t);
if (interceptedMethodTypeResult.HasDiagnostics)
{
@@ -151,7 +151,7 @@ public class BindingSourceGenerator : IIncrementalGenerator
var interceptableLocation = context.SemanticModel.GetInterceptableLocation(invocation, t);
#pragma warning restore RSEXPERIMENTAL002
- var sourceCodeLocation = SourceCodeLocation.CreateFrom(method.Name.GetLocation());
+ var sourceCodeLocation = SourceCodeLocation.CreateFrom(method.GetLocation());
diff --git a/src/Controls/src/BindingSourceGen/InvocationParser.cs b/src/Controls/src/BindingSourceGen/InvocationParser.cs
index 006103c280..8ab4542b26 100644
--- a/src/Controls/src/BindingSourceGen/InvocationParser.cs
+++ b/src/Controls/src/BindingSourceGen/InvocationParser.cs
@@ -18,9 +18,9 @@ internal class InvocationParser
internal const string Create = nameof(Create);
}
- internal Result<InterceptedMethodType> ParseInvocation(InvocationExpressionSyntax invocationSyntax, CancellationToken t)
+ internal Result<InterceptedMethodType> ParseInvocation(InvocationExpressionSyntax invocationSyntax, SimpleNameSyntax method, CancellationToken t)
{
- return ((MemberAccessExpressionSyntax)invocationSyntax.Expression).Name.Identifier.Text switch
+ return method.Identifier.Text switch
{
InterceptedMethodsNames.SetBinding => VerifyCorrectOverloadSetBinding(invocationSyntax, t),
InterceptedMethodsNames.Create => VerifyCorrectOverloadBindingCreate(invocationSyntax, t),Test command:
dotnet test src/Controls/tests/BindingSourceGen.UnitTests/Controls.BindingSourceGen.UnitTests.csproj --filter "FullyQualifiedName~BindingSourceGen.UnitTests.IntegrationTests"Test result: Pass on the first and only execution: 33 passed, 0 failed, 0 skipped.
Inline self-review: Clean, 0 findings (reviewer-findings.json contains []); the reviewed diff remained unchanged after testing.
Analysis: Selecting the common method-name node makes the provider independent of whether Roslyn encloses it in ordinary member access or conditional member binding. The transform can therefore reach semantic verification and interceptor generation without expression-shape normalization. This passed the bounded regression slice, though it changes the provider's candidate granularity and relies on syntax-parent relationships plus the terminal-span guard.
Artifacts: CustomAgentLogsTmp/PRState/38651/PRAgent/try-fix/attempt-2/
Restoration: EstablishBrokenBaseline.ps1 -Restore completed with Restored True; .github/.baseline-state.json was cleared and both target files had an empty working-tree diff.
🏁 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Winner: pr-plus-reviewer
The submitted production fix is correct and uses the strongest implementation design: one shared syntax-shape abstraction handles both ordinary member access and conditional member binding consistently across candidate filtering, location extraction, and parser dispatch. The expert reviewer found no actionable code defect and produced no inline findings. pr-plus-reviewer wins narrowly because it retains that implementation unchanged while strengthening the new regression test to prove that the null-conditional input emits the expected stable-ID SetBinding interceptor method.
Candidate Comparison
| Rank | Candidate | Mechanism | Regression evidence | Assessment |
|---|---|---|---|---|
| 1 | pr-plus-reviewer |
Submitted shared GetInvokedMethodName abstraction plus a generated-interceptor assertion |
Focused IntegrationTests: 33 passed, 0 failed, 0 skipped |
Best combination of centralized production logic and the most precise regression coverage |
| 2 | pr |
Shared helper maps MemberAccessExpressionSyntax and MemberBindingExpressionSyntax to SimpleNameSyntax |
Trusted Gate: regression fails without the fix and passes with it | Production fix is sound and minimal; test proves generation state and location, but not the emitted interceptor shape directly |
| 3 | try-fix-1 |
Repeats local syntax-shape switches at the predicate, transform, and parser | Focused IntegrationTests: 33 passed, 0 failed, 0 skipped |
Functional and localized, but duplicates the same Roslyn shape knowledge at three sites and is more vulnerable to future drift |
| 4 | try-fix-2 |
Changes the incremental provider to select SimpleNameSyntax and walks parent relationships to the invocation |
Focused IntegrationTests: 33 passed, 0 failed, 0 skipped |
Functional and conceptually distinct, but changes candidate granularity for both SetBinding and Create and relies on parent/span invariants, creating more regression surface than needed |
All four candidates passed their applicable regression evidence, so no candidate required the mandatory failed-test demotion. The ranking is therefore based on correctness clarity, maintenance cost, blast radius, and test precision.
Expert Review Reconciliation
- Inline findings: none (
inline-findings.jsonis[]). - Production behavior: the expert reviewer confirmed that null-conditional
SetBindingcalls now enter semantic verification and interceptor generation, directSetBindingremains unchanged, andBinding.Createfiltering is not broadened. - Reviewer refinement: only the generated-output assertion was actionable as an improvement; no production change was warranted.
- CI uncertainty: the expert pass could not independently observe GitHub required checks. The task's trusted Gate explicitly passed and demonstrated fail-without-fix/pass-with-fix behavior, so no additional Gate run was performed.
Required Change
Apply the two-line test refinement captured in pr-plus-reviewer/reviewer.patch. No changes to the submitted production implementation are recommended.
📱 UI Tests — Button,Label,Layout
Detected UI test categories: Button,Label,Layout
✅ Deep UI tests — 422 passed, 0 failed, 7 skipped across 3 categories on platform-pool agent (replaces in-process counts above).
🧪 UI Test Execution Results (deep, platform pool)
| Category | Tests | Snapshot diffs |
|---|---|---|
Button |
104/106 (2 skipped) ✓ | — |
Label |
123/125 (2 skipped) ✓ | — |
Layout |
195/198 (3 skipped) ✓ | — |
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs) |
🧭 Next Steps — reviewer changes required
The reviewer-enhanced candidate identified changes that are not yet in the submitted PR.
Why: The submitted shared-helper implementation is the clearest and lowest-risk production fix. pr-plus-reviewer preserves it unchanged and adds a focused assertion proving that the null-conditional case emits the expected stable-ID SetBinding interceptor, with all 33 targeted tests passing.
Address the actionable findings in this review before merging.
This comment has been minimized.
This comment has been minimized.
Tests Failure Analysis
🧪 CI Analysis — click to expand📊 maui-prNo failures found. 🧪 maui-pr-devicetests
🧪 maui-pr-uitests
🧭 Follow-up — actions and refreshNext action: Rerun the unresolved device legs and iOS Gestures shard, retaining the underlying build/crash diagnostics.
|
…#38651) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details label?.SetBinding(...) should create a compiled binding when label is not null. Instead, MAUI did not generate the required interceptor, so the app compiled but threw Call to SetBinding<...> was not intercepted at runtime. ### Root Cause label.SetBinding(...) and label?.SetBinding(...) have different C# syntax-tree shapes. The MAUI generator recognized only the ordinary call shape, so it skipped null-conditional calls and did not generate an interceptor. ### Description of Change GetInvokedMethodName now recognizes both syntax types. Therefore, ordinary and null-conditional SetBinding calls follow the same interceptor-generation process. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #38365 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/0c5a735d-4a06-4261-8488-f19f464a2be9" >| <video src="https://github.com/user-attachments/assets/b700be4b-776f-4def-bbd2-8325d1007bd1">|
…#38651) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details label?.SetBinding(...) should create a compiled binding when label is not null. Instead, MAUI did not generate the required interceptor, so the app compiled but threw Call to SetBinding<...> was not intercepted at runtime. ### Root Cause label.SetBinding(...) and label?.SetBinding(...) have different C# syntax-tree shapes. The MAUI generator recognized only the ordinary call shape, so it skipped null-conditional calls and did not generate an interceptor. ### Description of Change GetInvokedMethodName now recognizes both syntax types. Therefore, ordinary and null-conditional SetBinding calls follow the same interceptor-generation process. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #38365 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/0c5a735d-4a06-4261-8488-f19f464a2be9" >| <video src="https://github.com/user-attachments/assets/b700be4b-776f-4def-bbd2-8325d1007bd1">|
…#38651) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details label?.SetBinding(...) should create a compiled binding when label is not null. Instead, MAUI did not generate the required interceptor, so the app compiled but threw Call to SetBinding<...> was not intercepted at runtime. ### Root Cause label.SetBinding(...) and label?.SetBinding(...) have different C# syntax-tree shapes. The MAUI generator recognized only the ordinary call shape, so it skipped null-conditional calls and did not generate an interceptor. ### Description of Change GetInvokedMethodName now recognizes both syntax types. Therefore, ordinary and null-conditional SetBinding calls follow the same interceptor-generation process. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #38365 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/0c5a735d-4a06-4261-8488-f19f464a2be9" >| <video src="https://github.com/user-attachments/assets/b700be4b-776f-4def-bbd2-8325d1007bd1">|
…#38651) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details label?.SetBinding(...) should create a compiled binding when label is not null. Instead, MAUI did not generate the required interceptor, so the app compiled but threw Call to SetBinding<...> was not intercepted at runtime. ### Root Cause label.SetBinding(...) and label?.SetBinding(...) have different C# syntax-tree shapes. The MAUI generator recognized only the ordinary call shape, so it skipped null-conditional calls and did not generate an interceptor. ### Description of Change GetInvokedMethodName now recognizes both syntax types. Therefore, ordinary and null-conditional SetBinding calls follow the same interceptor-generation process. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #38365 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/0c5a735d-4a06-4261-8488-f19f464a2be9" >| <video src="https://github.com/user-attachments/assets/b700be4b-776f-4def-bbd2-8325d1007bd1">|
…#38651) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details label?.SetBinding(...) should create a compiled binding when label is not null. Instead, MAUI did not generate the required interceptor, so the app compiled but threw Call to SetBinding<...> was not intercepted at runtime. ### Root Cause label.SetBinding(...) and label?.SetBinding(...) have different C# syntax-tree shapes. The MAUI generator recognized only the ordinary call shape, so it skipped null-conditional calls and did not generate an interceptor. ### Description of Change GetInvokedMethodName now recognizes both syntax types. Therefore, ordinary and null-conditional SetBinding calls follow the same interceptor-generation process. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #38365 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/0c5a735d-4a06-4261-8488-f19f464a2be9" >| <video src="https://github.com/user-attachments/assets/b700be4b-776f-4def-bbd2-8325d1007bd1">|
…#38651) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details label?.SetBinding(...) should create a compiled binding when label is not null. Instead, MAUI did not generate the required interceptor, so the app compiled but threw Call to SetBinding<...> was not intercepted at runtime. ### Root Cause label.SetBinding(...) and label?.SetBinding(...) have different C# syntax-tree shapes. The MAUI generator recognized only the ordinary call shape, so it skipped null-conditional calls and did not generate an interceptor. ### Description of Change GetInvokedMethodName now recognizes both syntax types. Therefore, ordinary and null-conditional SetBinding calls follow the same interceptor-generation process. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #38365 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/0c5a735d-4a06-4261-8488-f19f464a2be9" >| <video src="https://github.com/user-attachments/assets/b700be4b-776f-4def-bbd2-8325d1007bd1">|
…#38651) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details label?.SetBinding(...) should create a compiled binding when label is not null. Instead, MAUI did not generate the required interceptor, so the app compiled but threw Call to SetBinding<...> was not intercepted at runtime. ### Root Cause label.SetBinding(...) and label?.SetBinding(...) have different C# syntax-tree shapes. The MAUI generator recognized only the ordinary call shape, so it skipped null-conditional calls and did not generate an interceptor. ### Description of Change GetInvokedMethodName now recognizes both syntax types. Therefore, ordinary and null-conditional SetBinding calls follow the same interceptor-generation process. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #38365 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/0c5a735d-4a06-4261-8488-f19f464a2be9" >| <video src="https://github.com/user-attachments/assets/b700be4b-776f-4def-bbd2-8325d1007bd1">|
…#38651) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details label?.SetBinding(...) should create a compiled binding when label is not null. Instead, MAUI did not generate the required interceptor, so the app compiled but threw Call to SetBinding<...> was not intercepted at runtime. ### Root Cause label.SetBinding(...) and label?.SetBinding(...) have different C# syntax-tree shapes. The MAUI generator recognized only the ordinary call shape, so it skipped null-conditional calls and did not generate an interceptor. ### Description of Change GetInvokedMethodName now recognizes both syntax types. Therefore, ordinary and null-conditional SetBinding calls follow the same interceptor-generation process. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #38365 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/0c5a735d-4a06-4261-8488-f19f464a2be9" >| <video src="https://github.com/user-attachments/assets/b700be4b-776f-4def-bbd2-8325d1007bd1">|
…#38651) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details label?.SetBinding(...) should create a compiled binding when label is not null. Instead, MAUI did not generate the required interceptor, so the app compiled but threw Call to SetBinding<...> was not intercepted at runtime. ### Root Cause label.SetBinding(...) and label?.SetBinding(...) have different C# syntax-tree shapes. The MAUI generator recognized only the ordinary call shape, so it skipped null-conditional calls and did not generate an interceptor. ### Description of Change GetInvokedMethodName now recognizes both syntax types. Therefore, ordinary and null-conditional SetBinding calls follow the same interceptor-generation process. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #38365 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/0c5a735d-4a06-4261-8488-f19f464a2be9" >| <video src="https://github.com/user-attachments/assets/b700be4b-776f-4def-bbd2-8325d1007bd1">|
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Issue Details
label?.SetBinding(...) should create a compiled binding when label is not null.
Instead, MAUI did not generate the required interceptor, so the app compiled but threw Call to SetBinding<...> was not intercepted at runtime.
Root Cause
label.SetBinding(...) and label?.SetBinding(...) have different C# syntax-tree shapes.
The MAUI generator recognized only the ordinary call shape, so it skipped null-conditional calls and did not generate an interceptor.
Description of Change
GetInvokedMethodName now recognizes both syntax types.
Therefore, ordinary and null-conditional SetBinding calls follow the same interceptor-generation process.
Validated the behavior in the following platforms
Issues Fixed
Fixes #38365
Output ScreenShot
38365-BeforeFix.mov
38365-AfterFix.mov