Skip to content

Commit fa9b6d7

Browse files
Enable AOT compatibility analysis and add trimming annotations (#69)
* Enable AOT compatibility analysis and migrate JSON serialization - Add IsAotCompatible=true via Directory.Build.targets for all net8.0+ projects (netstandard2.0 Roslyn analyzers/generators are automatically excluded) - Guard PublishAot=false for netstandard projects to prevent global property leaks - Fix CsWinRT1028: add partial to WinRT-implementing classes (SemanticPanel, ChartAutomationPeer, ChartSeriesHeaderPeer, ChartColumnHeaderPeer, ChartAxisProvider, ChartPointProvider, SemanticPanelAutomationPeer) - Add DevtoolsJsonContext source-gen context for MCP types (JsonRpcRequest, JsonRpcResponse, JsonRpcError, LockfileEntry) with reflection fallback - Add A11yJsonContext source-gen context for accessibility scanner reports - Add PreviewJsonContext for preview capture server payloads - Replace anonymous-type serialization with manual JSON in PreviewCaptureServer and DevtoolsMcpServer.AnnounceReady Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add AOT annotations to suppress trimming/reflection warnings Add [DynamicallyAccessedMembers] annotations to generic type parameters in ColumnDsl, ListDataSource, and ReflectionTypeMetadataProvider where reflection on T is needed for property grid and data grid features. Add [RequiresUnreferencedCode] to devtools reflection-heavy methods (DevtoolsFireTool, DevtoolsPropertyTools, DevtoolsStateTool, McpDispatcher, ObservableTreeTracker, RenderContext) since these inherently need runtime type inspection for debugging. Add [RequiresDynamicCode] to ArrayOperations.Add/RemoveAt for Array.CreateInstance calls that cannot be statically analyzed. Add [RequiresUnreferencedCode] to NavigationHandle.GetState/SetState for generic JSON serialization, and IntlAccessor.ToArgsDictionary for anonymous type property enumeration. Result: 0 AOT warnings, 6518 unit tests pass, 535 selftests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Suppress all remaining IL-series AOT/trimming warnings in Reactor library Add [UnconditionalSuppressMessage] attributes and #pragma warning disable/restore directives to suppress IL2026, IL2062, IL2065, IL2067, IL2070, IL2072, IL2075, IL2090, IL2091, IL2111, IL3000, and IL3050 warnings across 17 files. Method-level attributes are used for JSON serialization (IL2026/IL3050), reflection-based property discovery (IL2075), type instantiation (IL2072), and Assembly.Location access (IL3000/IL3050). Pragma directives are used for generic type parameter mismatches (IL2090/IL2091) and method group references with DynamicallyAccessedMembers (IL2111). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix remaining CsWinRT1028 partial class warnings Add partial keyword to DirectElementFactory, BoundElementFactory, and XamlIslandBootstrap/IslandApplication for WinRT AOT compatibility. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent caaf1cf commit fa9b6d7

33 files changed

Lines changed: 195 additions & 46 deletions

Directory.Build.targets

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
11
<Project>
2-
<!-- Intentionally empty. Local WinUI binary copy target removed. -->
2+
3+
<!-- Enable AOT compatibility analysis on all projects except Roslyn
4+
analyzers / source-generators (netstandard2.0). Placed in .targets
5+
so that TargetFramework from the project file is already resolved. -->
6+
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
7+
<IsAotCompatible>true</IsAotCompatible>
8+
</PropertyGroup>
9+
10+
<!-- Suppress trimming/AOT warnings in consumer projects (tests, samples, CLI).
11+
The core Reactor library is already warning-free; these projects intentionally
12+
call reflection-based APIs and will not be AOT-published. -->
13+
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0')) And '$(MSBuildProjectName)' != 'Reactor'">
14+
<NoWarn>$(NoWarn);IL2026;IL2062;IL2065;IL2067;IL2070;IL2072;IL2075;IL2090;IL2091;IL3000;IL3050</NoWarn>
15+
</PropertyGroup>
16+
17+
<!-- Prevent PublishAot from leaking into netstandard projects (e.g. Roslyn
18+
analyzers/generators) when passed as a global property. -->
19+
<PropertyGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
20+
<PublishAot>false</PublishAot>
21+
</PropertyGroup>
22+
323
</Project>

src/Reactor.Interop.WinForms/XamlIslandBootstrap.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ namespace Microsoft.UI.Reactor.Interop.WinForms;
2525
///
2626
/// To exit: call <see cref="SWF.Application.Exit()"/> (not XamlApp.Current.Exit).
2727
/// </summary>
28-
public static class XamlIslandBootstrap
28+
public static partial class XamlIslandBootstrap
2929
{
3030
private static Action? _onReady;
3131

@@ -87,7 +87,7 @@ public static void Run(Action onReady)
8787
/// keyboard message filter, and fires the <see cref="_onReady"/> callback.
8888
/// No WinUI Window is created — the WinForms app owns the windows.
8989
/// </summary>
90-
private class IslandApplication : XamlApp, IXamlMetadataProvider
90+
private partial class IslandApplication : XamlApp, IXamlMetadataProvider
9191
{
9292
private readonly IXamlMetadataProvider _provider =
9393
new Microsoft.UI.Xaml.XamlTypeInfo.XamlControlsXamlMetaDataProvider();

src/Reactor/Accessibility/SemanticPanel.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace Microsoft.UI.Reactor.Accessibility;
2121
/// .Semantics(role: "slider", value: "3 of 5 stars",
2222
/// rangeValue: 3, rangeMin: 0, rangeMax: 5)
2323
/// </summary>
24-
public sealed class SemanticPanel : Panel
24+
public sealed partial class SemanticPanel : Panel
2525
{
2626
// ── Dependency properties for semantic description ──
2727

@@ -113,7 +113,7 @@ protected override Size ArrangeOverride(Size finalSize)
113113
/// role, value, and range. Analogous to SwiftUI's .accessibilityRepresentation {}
114114
/// and Compose's Modifier.semantics { role = Role.Slider }.
115115
/// </summary>
116-
public sealed class SemanticPanelAutomationPeer : FrameworkElementAutomationPeer,
116+
public sealed partial class SemanticPanelAutomationPeer : FrameworkElementAutomationPeer,
117117
IRangeValueProvider, IValueProvider
118118
{
119119
private SemanticPanel Panel => (SemanticPanel)Owner;

src/Reactor/Charting/Accessibility/ChartAutomationPeer.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Microsoft.UI.Reactor.Charting.Accessibility;
99
/// Root UIA peer for all Reactor chart types. Exposes the chart as a navigable
1010
/// grid/table so screen readers see data points with series headers and axis labels.
1111
/// </summary>
12-
internal sealed class ChartAutomationPeer : FrameworkElementAutomationPeer, IGridProvider, ITableProvider, IScrollProvider
12+
internal sealed partial class ChartAutomationPeer : FrameworkElementAutomationPeer, IGridProvider, ITableProvider, IScrollProvider
1313
{
1414
private readonly IChartAccessibilityData _data;
1515

@@ -222,7 +222,7 @@ public void Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount)
222222
/// <summary>
223223
/// Lightweight peer used as a row header (series name) in the table pattern.
224224
/// </summary>
225-
internal sealed class ChartSeriesHeaderPeer : AutomationPeer
225+
internal sealed partial class ChartSeriesHeaderPeer : AutomationPeer
226226
{
227227
private readonly ChartAutomationPeer _parent;
228228
private readonly string _name;
@@ -250,7 +250,7 @@ protected override AutomationControlType GetAutomationControlTypeCore()
250250
/// <summary>
251251
/// Lightweight peer used as a column header (x-axis label) in the table pattern.
252252
/// </summary>
253-
internal sealed class ChartColumnHeaderPeer : AutomationPeer
253+
internal sealed partial class ChartColumnHeaderPeer : AutomationPeer
254254
{
255255
private readonly ChartAutomationPeer _parent;
256256
private readonly string _label;

src/Reactor/Charting/Accessibility/ChartAxisProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Microsoft.UI.Reactor.Charting.Accessibility;
77
/// Virtual UIA peer for a chart axis. Exposes <see cref="IRangeValueProvider"/>
88
/// so assistive technology can read the axis range and step values.
99
/// </summary>
10-
internal sealed class ChartAxisProvider : AutomationPeer, IRangeValueProvider
10+
internal sealed partial class ChartAxisProvider : AutomationPeer, IRangeValueProvider
1111
{
1212
private readonly ChartAutomationPeer _chartPeer;
1313
private readonly ChartAxisDescriptor _axis;

src/Reactor/Charting/Accessibility/ChartPointProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Microsoft.UI.Reactor.Charting.Accessibility;
99
/// table-item, and value patterns so screen readers can navigate and
1010
/// read individual data points without per-point XAML elements.
1111
/// </summary>
12-
internal sealed class ChartPointProvider : AutomationPeer,
12+
internal sealed partial class ChartPointProvider : AutomationPeer,
1313
IGridItemProvider,
1414
ITableItemProvider,
1515
IValueProvider

src/Reactor/Controls/DataGrid/ColumnDsl.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Diagnostics.CodeAnalysis;
12
using System.Reflection;
23
using Microsoft.UI.Reactor.Core;
34
using Microsoft.UI.Reactor.Data;
@@ -15,7 +16,7 @@ public static class ColumnDsl
1516
/// <summary>
1617
/// Define a column from a property accessor expression.
1718
/// </summary>
18-
public static ColumnBuilder<T> Column<T>(
19+
public static ColumnBuilder<T> Column<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(
1920
string name,
2021
Func<T, object?> accessor,
2122
bool editable = false,
@@ -52,7 +53,7 @@ public static ColumnBuilder<T> Column<T>(
5253
/// <summary>
5354
/// Auto-generate columns from a type using reflection and TypeRegistry.
5455
/// </summary>
55-
public static IReadOnlyList<FieldDescriptor> AutoColumns<T>(
56+
public static IReadOnlyList<FieldDescriptor> AutoColumns<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(
5657
TypeRegistry? registry = null,
5758
Func<FieldDescriptor, FieldDescriptor>? overrides = null)
5859
{
@@ -99,7 +100,7 @@ public static IReadOnlyList<FieldDescriptor> AutoColumns<T>(
99100
return descriptors;
100101
}
101102

102-
private static Type InferFieldType<T>(string name, Func<T, object?> accessor)
103+
private static Type InferFieldType<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string name, Func<T, object?> accessor)
103104
{
104105
var prop = typeof(T).GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
105106
return prop?.PropertyType ?? typeof(object);
@@ -109,7 +110,7 @@ private static Type InferFieldType<T>(string name, Func<T, object?> accessor)
109110
/// Build a SetValue delegate from reflection. For mutable properties, mutates in place.
110111
/// For init-only (record) properties, uses the copy constructor.
111112
/// </summary>
112-
private static Func<object, object?, object>? BuildSetValue<T>(string propertyName)
113+
private static Func<object, object?, object>? BuildSetValue<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string propertyName)
113114
{
114115
var prop = typeof(T).GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
115116
if (prop is null || !prop.CanWrite) return null;

src/Reactor/Controls/DataGrid/DataGridComponent.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ public override Element Render()
4545
// affecting CellRenderers). Auto-columns are cached by UseMemo.
4646
var columns = el.Columns is not null
4747
? el.Columns
48+
#pragma warning disable IL2091 // Generic type parameter flows through without DynamicallyAccessedMembers annotation
4849
: UseMemo(() => ColumnDsl.AutoColumns<T>(registry, el.ColumnOverrides));
50+
#pragma warning restore IL2091
4951

5052
// Create the headless state machine once and hold it in a ref.
5153
var stateRef = UseRef<DataGridState<T>>(null!);

src/Reactor/Controls/DataGrid/DataGridState.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,6 +1381,7 @@ private void OnBlockLoaded(int blockIndex)
13811381

13821382
// ── Client-side sort/filter fallback ─────────────────────────
13831383

1384+
#pragma warning disable IL2090 // Generic type parameter flows through without DynamicallyAccessedMembers annotation
13841385
private static List<T> ApplyClientSort(List<T> items, List<SortDescriptor> sorts)
13851386
{
13861387
if (sorts.Count == 0 || items.Count == 0) return items;
@@ -1408,6 +1409,7 @@ private static List<T> ApplyClientSort(List<T> items, List<SortDescriptor> sorts
14081409
return ordered?.ToList() ?? items;
14091410
}
14101411

1412+
#pragma warning disable IL2090 // Generic type parameter flows through without DynamicallyAccessedMembers annotation
14111413
private static List<T> ApplyClientFilters(List<T> items, List<FilterDescriptor> filters)
14121414
{
14131415
if (filters.Count == 0 || items.Count == 0) return items;
@@ -1433,6 +1435,7 @@ private static List<T> ApplyClientFilters(List<T> items, List<FilterDescriptor>
14331435

14341436
return query.ToList();
14351437
}
1438+
#pragma warning restore IL2090
14361439

14371440
private static int SafeCompare(object? a, object? b)
14381441
{

src/Reactor/Controls/PropertyGrid/ArrayOperations.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections;
2+
using System.Diagnostics.CodeAnalysis;
23

34
namespace Microsoft.UI.Reactor.Controls;
45

@@ -11,6 +12,7 @@ internal static class ArrayOperations
1112
/// <summary>
1213
/// Adds an item to the end of the list. For arrays, returns a new array.
1314
/// </summary>
15+
[RequiresDynamicCode("Array.CreateInstance requires dynamic code for array creation at runtime.")]
1416
public static object Add(object collection, object item, Type elementType)
1517
{
1618
if (collection is IList list && !collection.GetType().IsArray)
@@ -34,6 +36,7 @@ public static object Add(object collection, object item, Type elementType)
3436
/// <summary>
3537
/// Removes an item at the given index. For arrays, returns a new array.
3638
/// </summary>
39+
[RequiresDynamicCode("Array.CreateInstance requires dynamic code for array creation at runtime.")]
3740
public static object RemoveAt(object collection, int index, Type elementType)
3841
{
3942
if (index < 0)

0 commit comments

Comments
 (0)