fix(AOT): restore sidecar delivery and narrow linked fallbacks

This commit is contained in:
chinboy
2026-08-17 23:07:14 +08:00
parent 9593bf1537
commit 0d3d9727c6
24 changed files with 314 additions and 46 deletions
@@ -21,6 +21,14 @@ public sealed class GenerateLinkedRegistrationSidecarTask : ITask
public string TargetFramework { get; set; } = string.Empty;
/// <summary>
/// When true, the Sidecar is extracted by a consumer from a normally-built referenced
/// assembly. C# unit edges are only emitted by linked library builds, so each declared
/// package gets an ExtractedManifest fallback marker: the plan widens to full fallback
/// instead of trimming with incomplete evidence.
/// </summary>
public bool ExtractedFallback { get; set; }
[Output]
public string SidecarPath { get; private set; } = string.Empty;
@@ -67,6 +75,19 @@ public sealed class GenerateLinkedRegistrationSidecarTask : ITask
return LogError(error);
}
sidecar.Assembly.TargetFramework = TargetFramework.Trim();
if (ExtractedFallback && sidecar.Packages.Length != 0)
{
sidecar.Fallbacks = sidecar.Fallbacks
.Concat(sidecar.Packages.Select(static package => new LinkedSidecarFallback
{
PackageId = package.Id,
Reason = LinkedRegistrationProtocol.FallbackReasonExtractedManifest,
Source = "<extraction>",
Line = 0,
Column = 0
}))
.ToArray();
}
var bytes = LinkedRegistrationSidecarCodec.Write(sidecar);
if (analysisBudgetExceeded ||
bytes.Length > LinkedRegistrationAnalysisBudget.MaxSidecarBytes)
+18 -7
View File
@@ -48,8 +48,11 @@ public static class AppBuilderExtensions
/// </example>
public static AppBuilder WithAtomUIDefaultOptions(this AppBuilder appBuilder)
{
return appBuilder
.With(new AvaloniaNativePlatformOptions
// 按目标平台分支设置平台选项。NativeAOT 在 RID 发布时会把 OperatingSystem.IsXxx()
// 折叠为常量,非目标平台的分支及其引用的平台选项类型会被整体裁剪。
if (OperatingSystem.IsMacOS())
{
appBuilder = appBuilder.With(new AvaloniaNativePlatformOptions
{
RenderingMode =
[
@@ -57,8 +60,11 @@ public static class AppBuilderExtensions
AvaloniaNativeRenderingMode.Metal,
AvaloniaNativeRenderingMode.Software
]
})
.With(new Win32PlatformOptions
});
}
if (OperatingSystem.IsWindows())
{
appBuilder = appBuilder.With(new Win32PlatformOptions
{
RenderingMode =
[
@@ -66,11 +72,16 @@ public static class AppBuilderExtensions
Win32RenderingMode.Software
],
CompositionMode = [Win32CompositionMode.RedirectionSurface]
})
.With(new X11PlatformOptions
});
}
if (OperatingSystem.IsLinux())
{
appBuilder = appBuilder.With(new X11PlatformOptions
{
EnableDrawnDecorations = true
})
});
}
return appBuilder
.With(new FontManagerOptions
{
FontFallbacks = [new FontFallback
+1 -2
View File
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(AtomUITargetFrameworks)</TargetFrameworks>
<RootNamespace>AtomUI</RootNamespace>
@@ -26,7 +26,6 @@
<PackageReference Include="Avalonia.Native" />
<PackageReference Include="Avalonia.Win32" />
<PackageReference Include="Avalonia"/>
<PackageReference Include="ReactiveUI.Avalonia"/>
<PackageReference Include="System.Reactive"/>
</ItemGroup>
@@ -86,7 +86,7 @@ public sealed class LinkedRegistrationPackageManifestGenerator : IIncrementalGen
{
fallbacks.Add(new Fallback(
packageId,
"DynamicInvocation",
LinkedRegistrationProtocol.FallbackReasonDynamicInvocation,
NormalizeSourcePath(candidate.Source, projectDirectory),
candidate.Line,
candidate.Column,
@@ -376,7 +376,12 @@ public sealed class LinkedRegistrationPackageManifestGenerator : IIncrementalGen
AnalyzerConfigOptionsProvider optionsProvider,
Fallback fallback)
{
var descriptor = AtomUIDiagnosticDescriptors.LinkedDynamicUsageWidened;
var descriptor = string.Equals(
fallback.Reason,
LinkedRegistrationProtocol.FallbackReasonDynamicInvocation,
StringComparison.Ordinal)
? AtomUIDiagnosticDescriptors.LinkedDynamicUsageUncovered
: AtomUIDiagnosticDescriptors.LinkedDynamicUsageWidened;
if (LinkedRegistrationOptions.IsRegistrationStrict(optionsProvider))
{
descriptor = new DiagnosticDescriptor(
@@ -86,6 +86,15 @@ internal static class AtomUIDiagnosticDescriptors
isEnabledByDefault: true,
customTags: [WellKnownDiagnosticTags.Telemetry]);
public static readonly DiagnosticDescriptor LinkedDynamicUsageUncovered = new(
AtomUIDiagnosticIds.LinkedDynamicUsageUncovered,
"Dynamic AtomUI usage is not covered by the static registration plan",
"AtomUI dynamic usage '{0}' cannot be resolved statically; controls of Package '{1}' created only through this site are not registered. Add an AtomUIRegistrationUnitRoot when the Unit is known, or an AtomUIPackageRoot for fully dynamic usage; no action is required when this site never creates AtomUI controls.",
AtomUIDiagnosticCategories.LinkedRegistration,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
customTags: [WellKnownDiagnosticTags.Telemetry]);
public static readonly DiagnosticDescriptor AotMissingGeneratedAccessor = new(
AtomUIDiagnosticIds.AotMissingGeneratedAccessor,
"AOT-sensitive data member path requires generated accessor",
@@ -40,4 +40,5 @@ internal static class AtomUIDiagnosticIds
public const string LinkedLooseAxamlWidened = "ATOMUILINK007";
public const string LinkedPackageEntryMissing = "ATOMUILINK008";
public const string LinkedPackageEntryInvalid = "ATOMUILINK009";
public const string LinkedDynamicUsageUncovered = "ATOMUILINK010";
}
@@ -117,8 +117,16 @@ public sealed class ApplicationRegistrationPlanGenerator : IIncrementalGenerator
usage.Kind == LinkedUsageKind.PackageRoot &&
string.Equals(usage.Identity, packageId, StringComparison.Ordinal)) ||
catalog.Fallbacks.Any(fallback =>
fallback.PackageId.Length == 0 ||
string.Equals(fallback.PackageId, packageId, StringComparison.Ordinal));
// Unresolvable C# dynamic creation (DynamicInvocation) is reported as
// guidance (ATOMUILINK010) but never widens the plan: application-declared
// controls are already covered by base-type evidence, and purely
// string-driven creation is covered by explicit Unit/Package roots.
!string.Equals(
fallback.Reason,
LinkedRegistrationProtocol.FallbackReasonDynamicInvocation,
StringComparison.Ordinal) &&
(fallback.PackageId.Length == 0 ||
string.Equals(fallback.PackageId, packageId, StringComparison.Ordinal)));
if (isLegacy)
{
if (ValidateFragmentMethod(
@@ -231,12 +239,29 @@ public sealed class ApplicationRegistrationPlanGenerator : IIncrementalGenerator
.ThenBy(static item => item.Column)
.ThenBy(static item => item.Reason, StringComparer.Ordinal))
{
// ExtractedManifest marks a consumer-extracted ProjectReference Sidecar: the plan
// already widened to full fallback, and the delivery mode is not a code problem.
if (string.Equals(
fallback.Reason,
LinkedRegistrationProtocol.FallbackReasonExtractedManifest,
StringComparison.Ordinal))
{
continue;
}
if (fallback.PackageId.Length != 0 && !invokedPackageSet.Contains(fallback.PackageId))
{
continue;
}
var baseDescriptor = string.Equals(
fallback.Reason,
LinkedRegistrationProtocol.FallbackReasonDynamicInvocation,
StringComparison.Ordinal)
? AtomUIDiagnosticDescriptors.LinkedDynamicUsageUncovered
: AtomUIDiagnosticDescriptors.LinkedDynamicUsageWidened;
context.ReportDiagnostic(Diagnostic.Create(
GetFallbackDescriptor(LinkedRegistrationOptions.IsRegistrationStrict(optionsProvider)),
GetFallbackDescriptor(
LinkedRegistrationOptions.IsRegistrationStrict(optionsProvider),
baseDescriptor),
Location.None,
fallback.Reason,
fallback.PackageId.Length == 0 ? "<all invoked packages>" : fallback.PackageId));
@@ -379,13 +404,12 @@ public sealed class ApplicationRegistrationPlanGenerator : IIncrementalGenerator
descriptor.CustomTags.ToArray());
}
private static DiagnosticDescriptor GetFallbackDescriptor(bool strict)
private static DiagnosticDescriptor GetFallbackDescriptor(bool strict, DiagnosticDescriptor descriptor)
{
if (!strict)
{
return AtomUIDiagnosticDescriptors.LinkedDynamicUsageWidened;
return descriptor;
}
var descriptor = AtomUIDiagnosticDescriptors.LinkedDynamicUsageWidened;
return new DiagnosticDescriptor(
descriptor.Id,
descriptor.Title,
@@ -12,4 +12,13 @@ internal static class LinkedRegistrationProtocol
internal const string UsageManifestKey = MetadataPrefix + "Usage.v1";
internal const string FallbackManifestKey = MetadataPrefix + "Fallback.v1";
internal const string PlanMarkerKey = MetadataPrefix + "Plan.v1";
internal const string FallbackReasonAnalysisBudgetExceeded = "AnalysisBudgetExceeded";
internal const string FallbackReasonDynamicInvocation = "DynamicInvocation";
internal const string FallbackReasonUnresolvedOwner = "UnresolvedOwner";
// Sidecar extracted by the consumer from assembly metadata of a normally-built
// ProjectReference: package/unit manifests are complete, but C# unit edges are only
// computed by linked library builds. The plan must widen to full fallback for these
// packages, and the reason is never surfaced as a diagnostic.
internal const string FallbackReasonExtractedManifest = "ExtractedManifest";
}
@@ -387,14 +387,15 @@ public sealed class LinkedRegistrationUsageGenerator : IIncrementalGenerator
static packageId => packageId,
StringComparer.Ordinal))
{
AddPackageFallback(
packageId,
dynamicUse.Source,
dynamicUse.Line,
dynamicUse.Column,
// C# dynamic creation sites no longer widen the package: controls declared
// in the application are already covered by base-type evidence, and purely
// string-driven creation is covered by explicit Unit/Package roots. Report
// guidance only.
ReportFallback(
AtomUIDiagnosticDescriptors.LinkedDynamicUsageUncovered,
dynamicUse.Location,
AtomUIDiagnosticDescriptors.LinkedDynamicUsageWidened,
dynamicUse.Identity);
dynamicUse.Identity,
packageId);
}
}