-
Notifications
You must be signed in to change notification settings - Fork 1.9k
[XSG] Fix invalid code generation for Setter with OnPlatform without Default #33681
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" | ||
| xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | ||
| x:Class="Microsoft.Maui.Controls.Xaml.UnitTests.Maui33676"> | ||
| <ContentPage.Resources> | ||
| <!-- This should work when building for iOS --> | ||
| <Style TargetType="Label" x:Key="iOSOnlyStyle"> | ||
| <Setter Property="Margin" Value="{OnPlatform iOS='0, 4, 0, 0'}" /> | ||
| </Style> | ||
| <!-- This should also work when building for Android (no matching platform, no Default) --> | ||
| </ContentPage.Resources> | ||
| <Label x:Name="label" Style="{StaticResource iOSOnlyStyle}"/> | ||
| </ContentPage> |
96 changes: 96 additions & 0 deletions
96
src/Controls/tests/Xaml.UnitTests/Issues/Maui33676.xaml.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| using System; | ||
| using Microsoft.Maui.Controls.Core.UnitTests; | ||
| using Microsoft.Maui.Devices; | ||
| using Xunit; | ||
|
|
||
| using static Microsoft.Maui.Controls.Xaml.UnitTests.MockSourceGenerator; | ||
|
|
||
| namespace Microsoft.Maui.Controls.Xaml.UnitTests; | ||
|
|
||
| public partial class Maui33676 : ContentPage | ||
| { | ||
| public Maui33676() => InitializeComponent(); | ||
|
|
||
| [Collection("Issue")] | ||
| public class Tests : IDisposable | ||
| { | ||
| MockDeviceInfo mockDeviceInfo; | ||
|
|
||
| public Tests() => DeviceInfo.SetCurrent(mockDeviceInfo = new MockDeviceInfo()); | ||
|
|
||
| public void Dispose() => DeviceInfo.SetCurrent(null); | ||
|
|
||
| [Theory] | ||
| [XamlInflatorData] | ||
| // BUG: When a Setter uses OnPlatform without a Default value and the target platform | ||
| // doesn't match any of the specified platforms, SourceGen generates invalid code: | ||
| // ((IValueProvider)).ProvideValue(...) - trying to call a method on a type instead of an instance | ||
| // | ||
| // Expected behavior: The Setter should be skipped entirely or use a default value | ||
| internal void SetterWithOnPlatformWithoutDefaultShouldNotGenerateInvalidCode(XamlInflator inflator) | ||
| { | ||
| // Test compiling for Android when OnPlatform only specifies iOS | ||
| if (inflator == XamlInflator.SourceGen) | ||
| { | ||
| var result = CreateMauiCompilation() | ||
| .WithAdditionalSource( | ||
| """ | ||
| namespace Microsoft.Maui.Controls.Xaml.UnitTests; | ||
|
|
||
| public partial class Maui33676 : ContentPage | ||
| { | ||
| public Maui33676() => InitializeComponent(); | ||
| } | ||
| """) | ||
| .RunMauiSourceGenerator(typeof(Maui33676), targetFramework: "net10.0-android"); | ||
|
|
||
| var generated = result.GeneratedInitializeComponent(); | ||
|
|
||
| // BUG: Generated code contains invalid C# like: | ||
| // ((global::Microsoft.Maui.Controls.Xaml.IValueProvider)).ProvideValue(...) | ||
| // This causes: CS0119 'IValueProvider' is a type, which is not valid in the given context | ||
| // This should NOT happen - when OnPlatform has no matching value, the Setter should be omitted | ||
| Assert.DoesNotContain("((global::Microsoft.Maui.Controls.Xaml.IValueProvider)).ProvideValue", generated, StringComparison.Ordinal); | ||
|
|
||
| Assert.Empty(result.Diagnostics); | ||
| } | ||
| else | ||
| { | ||
| mockDeviceInfo.Platform = DevicePlatform.Android; | ||
| var page = new Maui33676(inflator); | ||
| Assert.NotNull(page); | ||
| } | ||
| } | ||
|
|
||
| [Theory] | ||
| [XamlInflatorData] | ||
| // When the platform DOES match, the Setter should work correctly | ||
| internal void SetterWithOnPlatformMatchingPlatform(XamlInflator inflator) | ||
StephaneDelcroix marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| if (inflator == XamlInflator.SourceGen) | ||
| { | ||
| var result = CreateMauiCompilation() | ||
| .WithAdditionalSource( | ||
| """ | ||
| namespace Microsoft.Maui.Controls.Xaml.UnitTests; | ||
|
|
||
| public partial class Maui33676 : ContentPage | ||
| { | ||
| public Maui33676() => InitializeComponent(); | ||
| } | ||
| """) | ||
| .RunMauiSourceGenerator(typeof(Maui33676), targetFramework: "net10.0-ios"); | ||
|
|
||
| Assert.Empty(result.Diagnostics); | ||
| var generated = result.GeneratedInitializeComponent(); | ||
| Assert.Contains("0, 4, 0, 0", generated, StringComparison.Ordinal); | ||
| } | ||
| else | ||
| { | ||
| mockDeviceInfo.Platform = DevicePlatform.iOS; | ||
| var page = new Maui33676(inflator); | ||
| Assert.NotNull(page); | ||
| } | ||
| } | ||
| } | ||
| } | ||
25 changes: 25 additions & 0 deletions
25
src/Controls/tests/Xaml.UnitTests/Issues/Maui33676_VisualState.xaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" | ||
| xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | ||
| x:Class="Microsoft.Maui.Controls.Xaml.UnitTests.Maui33676_VisualState"> | ||
| <ContentPage.Resources> | ||
| <Color x:Key="Gray950">#0D0D0D</Color> | ||
| <Color x:Key="Gray200">#E0E0E0</Color> | ||
| <Style TargetType="Button" x:Key="ButtonWithVisualState"> | ||
| <Setter Property="VisualStateManager.VisualStateGroups"> | ||
| <VisualStateGroupList> | ||
| <VisualStateGroup x:Name="CommonStates"> | ||
| <VisualState x:Name="Normal" /> | ||
| <VisualState x:Name="Disabled"> | ||
| <VisualState.Setters> | ||
| <Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" /> | ||
| <Setter Property="BackgroundColor" Value="{OnPlatform Android='Red'}" /> | ||
| </VisualState.Setters> | ||
| </VisualState> | ||
| </VisualStateGroup> | ||
| </VisualStateGroupList> | ||
| </Setter> | ||
| </Style> | ||
| </ContentPage.Resources> | ||
| <Button x:Name="button" Style="{StaticResource ButtonWithVisualState}"/> | ||
| </ContentPage> |
61 changes: 61 additions & 0 deletions
61
src/Controls/tests/Xaml.UnitTests/Issues/Maui33676_VisualState.xaml.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| using System; | ||
| using Microsoft.Maui.Controls.Core.UnitTests; | ||
| using Microsoft.Maui.Devices; | ||
| using Xunit; | ||
|
|
||
| using static Microsoft.Maui.Controls.Xaml.UnitTests.MockSourceGenerator; | ||
|
|
||
| namespace Microsoft.Maui.Controls.Xaml.UnitTests; | ||
|
|
||
| public partial class Maui33676_VisualState : ContentPage | ||
| { | ||
| public Maui33676_VisualState() => InitializeComponent(); | ||
|
|
||
| [Collection("Issue")] | ||
| public class Tests : IDisposable | ||
| { | ||
| MockDeviceInfo mockDeviceInfo; | ||
|
|
||
| public Tests() => DeviceInfo.SetCurrent(mockDeviceInfo = new MockDeviceInfo()); | ||
|
|
||
| public void Dispose() => DeviceInfo.SetCurrent(null); | ||
|
|
||
| [Theory] | ||
| [XamlInflatorData] | ||
| // When a Setter inside VisualState uses OnPlatform without a Default value and the target platform | ||
| // doesn't match, SourceGen should handle it gracefully | ||
| internal void SetterInVisualStateWithOnPlatformWithoutDefaultShouldNotGenerateInvalidCode(XamlInflator inflator) | ||
| { | ||
| // Test compiling for MacCatalyst when OnPlatform only specifies Android | ||
| if (inflator == XamlInflator.SourceGen) | ||
| { | ||
| var result = CreateMauiCompilation() | ||
| .WithAdditionalSource( | ||
| """ | ||
| namespace Microsoft.Maui.Controls.Xaml.UnitTests; | ||
|
|
||
| public partial class Maui33676_VisualState : ContentPage | ||
| { | ||
| public Maui33676_VisualState() => InitializeComponent(); | ||
| } | ||
| """) | ||
| .RunMauiSourceGenerator(typeof(Maui33676_VisualState), targetFramework: "net10.0-maccatalyst"); | ||
|
|
||
| var generated = result.GeneratedInitializeComponent(); | ||
|
|
||
| // Check that we're NOT generating code that tries to add object to IList<Setter> | ||
| // This would happen if IValueProvider.ProvideValue() is called on a Setter with no value | ||
| Assert.DoesNotContain("((global::Microsoft.Maui.Controls.Xaml.IValueProvider)).ProvideValue", generated, StringComparison.Ordinal); | ||
|
|
||
| // Should not have any compilation errors | ||
| Assert.Empty(result.Diagnostics); | ||
| } | ||
| else | ||
| { | ||
| mockDeviceInfo.Platform = DevicePlatform.macOS; | ||
| var page = new Maui33676_VisualState(inflator); | ||
| Assert.NotNull(page); | ||
| } | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.