Skip to content

Commit 1926f09

Browse files
authored
Annotating System.Diagnostics.DiagnosticSource on AOT (#72706)
* Annotating System.Diagnostics.DiagnosticSource on AOT * FB + enable tests * FB * warning message FB * comment FB2 * Warning message revision to reflect AOT problems at code generation
1 parent c1357bc commit 1926f09

14 files changed

+61
-2
lines changed

src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSource.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public virtual void Dispose() { }
2020
public virtual System.IDisposable Subscribe(System.IObserver<System.Collections.Generic.KeyValuePair<string, object?>> observer, System.Predicate<string>? isEnabled) { throw null; }
2121
public override string ToString() { throw null; }
2222
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("The type of object being written to DiagnosticSource cannot be discovered statically.")]
23+
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("DiagnosticSource may require creating new generic types or methods, which requires creating code at runtime. This may not work when AOT compiling.")]
2324
public override void Write(string name, object? value) { }
2425
}
2526
public abstract partial class DiagnosticSource
@@ -28,6 +29,7 @@ protected DiagnosticSource() { }
2829
public abstract bool IsEnabled(string name);
2930
public virtual bool IsEnabled(string name, object? arg1, object? arg2 = null) { throw null; }
3031
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("The type of object being written to DiagnosticSource cannot be discovered statically.")]
32+
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("DiagnosticSource may require creating new generic types or methods, which requires creating code at runtime. This may not work when AOT compiling.")]
3133
public abstract void Write(string name, object? value);
3234
}
3335
}

src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSource.csproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
44
<CLSCompliant>false</CLSCompliant>
@@ -15,6 +15,10 @@
1515
<Compile Include="$(CoreLibSharedDir)System\Runtime\CompilerServices\IsExternalInit.cs" />
1616
</ItemGroup>
1717

18+
<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">
19+
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\RequiresDynamicCodeAttribute.cs" />
20+
</ItemGroup>
21+
1822
<ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)'">
1923
<ProjectReference Include="$(LibrariesProjectRoot)System.Runtime\ref\System.Runtime.csproj" />
2024
</ItemGroup>

src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,10 @@ public abstract partial class DiagnosticSource
197197
public virtual void OnActivityExport(System.Diagnostics.Activity activity, object? payload) { }
198198
public virtual void OnActivityImport(System.Diagnostics.Activity activity, object? payload) { }
199199
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("The type of object being written to DiagnosticSource cannot be discovered statically.")]
200+
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("DiagnosticSource may require creating new generic types or methods, which requires creating code at runtime. This may not work when AOT compiling.")]
200201
public System.Diagnostics.Activity StartActivity(System.Diagnostics.Activity activity, object? args) { throw null; }
201202
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("The type of object being written to DiagnosticSource cannot be discovered statically.")]
203+
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("DiagnosticSource may require creating new generic types or methods, which requires creating code at runtime. This may not work when AOT compiling.")]
202204
public void StopActivity(System.Diagnostics.Activity activity, object? args) { }
203205
}
204206
public enum ActivitySamplingResult

src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<IsPackable>true</IsPackable>
99
<!-- Lifetime rules introduced in C# 11 impact scenarios in net6 framework -->
1010
<LangVersion Condition="'$(TargetFramework)' == 'net6.0'">10</LangVersion>
11+
<EnableAOTAnalyzer>true</EnableAOTAnalyzer>
1112
<PackageDescription>Provides Classes that allow you to decouple code logging rich (unserializable) diagnostics/telemetry (e.g. framework) from code that consumes it (e.g. tools)
1213

1314
Commonly Used Types:
@@ -103,6 +104,10 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
103104
<Compile Include="$(CoreLibSharedDir)System\Runtime\CompilerServices\IsExternalInit.cs" />
104105
</ItemGroup>
105106

107+
<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))" >
108+
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\RequiresDynamicCodeAttribute.cs" />
109+
</ItemGroup>
110+
106111
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' or
107112
'$(TargetFramework)' == 'netstandard2.0'">
108113
<Compile Include="System\Diagnostics\Activity.DateTime.corefx.cs" />

src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticListener.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ public partial class DiagnosticListener : DiagnosticSource, IObservable<KeyValue
3434
/// </summary>
3535
public static IObservable<DiagnosticListener> AllListeners
3636
{
37+
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
38+
Justification = "ENABLE_HTTP_HANDLER is not enabled in the .NET current version")]
3739
get
3840
{
3941
#if ENABLE_HTTP_HANDLER
@@ -253,6 +255,7 @@ public override bool IsEnabled(string name, object? arg1, object? arg2 = null)
253255
/// Override abstract method
254256
/// </summary>
255257
[RequiresUnreferencedCode(WriteRequiresUnreferencedCode)]
258+
[RequiresDynamicCode(WriteRequiresDynamicCode)]
256259
public override void Write(string name, object? value)
257260
{
258261
for (DiagnosticSubscription? curSubscription = _subscriptions; curSubscription != null; curSubscription = curSubscription.Next)

src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticSource.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace System.Diagnostics
1717
public abstract partial class DiagnosticSource
1818
{
1919
internal const string WriteRequiresUnreferencedCode = "The type of object being written to DiagnosticSource cannot be discovered statically.";
20+
internal const string WriteRequiresDynamicCode = "DiagnosticSource may require creating new generic types or methods, which requires creating code at runtime. This may not work when AOT compiling.";
2021

2122
/// <summary>
2223
/// Write is a generic way of logging complex payloads. Each notification
@@ -35,6 +36,7 @@ public abstract partial class DiagnosticSource
3536
/// <param name="value">An object that represent the value being passed as a payload for the event.
3637
/// This is often an anonymous type which contains several sub-values.</param>
3738
[RequiresUnreferencedCode(WriteRequiresUnreferencedCode)]
39+
[RequiresDynamicCode(WriteRequiresDynamicCode)]
3840
public abstract void Write(string name, object? value);
3941

4042
/// <summary>

src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticSourceActivity.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public abstract partial class DiagnosticSource
2626
/// <returns>Started Activity for convenient chaining</returns>
2727
/// <seealso cref="Activity"/>
2828
[RequiresUnreferencedCode(WriteRequiresUnreferencedCode)]
29+
[RequiresDynamicCode(WriteRequiresDynamicCode)]
2930
public Activity StartActivity(Activity activity, object? args)
3031
{
3132
activity.Start();
@@ -44,6 +45,7 @@ public Activity StartActivity(Activity activity, object? args)
4445
/// <param name="args">An object that represent the value being passed as a payload for the event.</param>
4546
/// <seealso cref="Activity"/>
4647
[RequiresUnreferencedCode(WriteRequiresUnreferencedCode)]
48+
[RequiresDynamicCode(WriteRequiresDynamicCode)]
4749
public void StopActivity(Activity activity, object? args)
4850
{
4951
// Stop sets the end time if it was unset, but we want it set before we issue the write

src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticSourceEventSource.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,8 @@ public FilterAndTransform(string filterAndPayloadSpec, int startIdx, int endIdx,
641641
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2119",
642642
Justification = "DAM on EventSource references this compiler-generated local function which calls a " +
643643
"method that requires unreferenced code. EventSource will not access this local function.")]
644+
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
645+
Justification = "DiagnosticSource.Write is marked with RequiresDynamicCode.")]
644646
void OnEventWritten(KeyValuePair<string, object?> evnt)
645647
{
646648
// The filter given to the DiagnosticSource may not work if users don't is 'IsEnabled' as expected.
@@ -888,6 +890,8 @@ internal static void CreateActivityListener(DiagnosticSourceEventSource eventSou
888890
[DynamicDependency(nameof(TimeSpan.Ticks), typeof(TimeSpan))]
889891
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
890892
Justification = "Activity's properties are being preserved with the DynamicDependencies on OnActivityStarted.")]
893+
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
894+
Justification = "Activity is a reference type and is safe in aot.")]
891895
private static void OnActivityStarted(DiagnosticSourceEventSource eventSource, Activity activity)
892896
{
893897
FilterAndTransform? list = eventSource._activitySourceSpecs;
@@ -907,6 +911,8 @@ private static void OnActivityStarted(DiagnosticSourceEventSource eventSource, A
907911

908912
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
909913
Justification = "Activity's properties are being preserved with the DynamicDependencies on OnActivityStarted.")]
914+
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
915+
Justification = "Activity is a reference type and is safe with aot.")]
910916
private static void OnActivityStopped(DiagnosticSourceEventSource eventSource, Activity activity)
911917
{
912918
FilterAndTransform? list = eventSource._activitySourceSpecs;
@@ -1009,6 +1015,7 @@ private void Dispose()
10091015
Justification = "In EventSource, EnsureDescriptorsInitialized's use of GetType preserves this method which " +
10101016
"requires unreferenced code, but EnsureDescriptorsInitialized does not access this member and is safe to call.")]
10111017
[RequiresUnreferencedCode(DiagnosticSource.WriteRequiresUnreferencedCode)]
1018+
[RequiresDynamicCode(DiagnosticSource.WriteRequiresDynamicCode)]
10121019
public List<KeyValuePair<string, string?>> Morph(object? args)
10131020
{
10141021
// Transform the args into a bag of key-value strings.
@@ -1190,6 +1197,7 @@ public TransformSpec(string transformSpec, int startIdx, int endIdx, TransformSp
11901197
Justification = "In EventSource, EnsureDescriptorsInitialized's use of GetType preserves this method which " +
11911198
"requires unreferenced code, but EnsureDescriptorsInitialized does not access this member and is safe to call.")]
11921199
[RequiresUnreferencedCode(DiagnosticSource.WriteRequiresUnreferencedCode)]
1200+
[RequiresDynamicCode(DiagnosticSource.WriteRequiresDynamicCode)]
11931201
public KeyValuePair<string, string?> Morph(object? obj)
11941202
{
11951203
for (PropertySpec? cur = _fetches; cur != null; cur = cur.Next)
@@ -1244,6 +1252,7 @@ public PropertySpec(string propertyName, PropertySpec? next)
12441252
Justification = "In EventSource, EnsureDescriptorsInitialized's use of GetType preserves this method which " +
12451253
"requires unreferenced code, but EnsureDescriptorsInitialized does not access this member and is safe to call.")]
12461254
[RequiresUnreferencedCode(DiagnosticSource.WriteRequiresUnreferencedCode)]
1255+
[RequiresDynamicCode(DiagnosticSource.WriteRequiresDynamicCode)]
12471256
public object? Fetch(object? obj)
12481257
{
12491258
PropertyFetch? fetch = _fetchForExpectedType;
@@ -1290,6 +1299,7 @@ public PropertyFetch(Type? type)
12901299
Justification = "In EventSource, EnsureDescriptorsInitialized's use of GetType preserves this method which " +
12911300
"requires unreferenced code, but EnsureDescriptorsInitialized does not access this member and is safe to call.")]
12921301
[RequiresUnreferencedCode(DiagnosticSource.WriteRequiresUnreferencedCode)]
1302+
[RequiresDynamicCode(DiagnosticSource.WriteRequiresDynamicCode)]
12931303
public static PropertyFetch FetcherForProperty(Type? type, string propertyName)
12941304
{
12951305
if (propertyName == null)

src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/HttpHandlerDiagnosticListener.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Collections;
55
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
67
using System.Net;
78
using System.Reflection;
89
using System.Reflection.Emit;
@@ -24,6 +25,7 @@ namespace System.Diagnostics
2425
/// when it sees the System.Net.Http.Desktop source, subscribe to it. This will trigger the
2526
/// initialization of this DiagnosticListener.
2627
/// </summary>
28+
[RequiresDynamicCode(WriteRequiresDynamicCode)]
2729
internal sealed class HttpHandlerDiagnosticListener : DiagnosticListener
2830
{
2931
/// <summary>
@@ -202,6 +204,7 @@ public override void Remove(object key)
202204
/// intercept each new ServicePoint object being added to ServicePointManager.s_ServicePointTable
203205
/// and replace its ConnectionGroupList hashtable field.
204206
/// </summary>
207+
[RequiresDynamicCode(WriteRequiresDynamicCode)]
205208
private sealed class ServicePointHashtable : HashtableWrapper
206209
{
207210
public ServicePointHashtable(Hashtable table) : base(table)
@@ -242,6 +245,7 @@ public override object this[object key]
242245
/// intercept each new ConnectionGroup object being added to ServicePoint.m_ConnectionGroupList
243246
/// and replace its m_ConnectionList arraylist field.
244247
/// </summary>
248+
[RequiresDynamicCode(WriteRequiresDynamicCode)]
245249
private sealed class ConnectionGroupHashtable : HashtableWrapper
246250
{
247251
public ConnectionGroupHashtable(Hashtable table) : base(table)
@@ -481,6 +485,7 @@ public override void TrimToSize()
481485
/// intercept each new Connection object being added to ConnectionGroup.m_ConnectionList
482486
/// and replace its m_WriteList arraylist field.
483487
/// </summary>
488+
[RequiresDynamicCode(WriteRequiresDynamicCode)]
484489
private sealed class ConnectionArrayList : ArrayListWrapper
485490
{
486491
public ConnectionArrayList(ArrayList list) : base(list)
@@ -511,6 +516,7 @@ public override int Add(object value)
511516
/// It also intercepts all HttpWebRequest objects that are about to get removed from
512517
/// Connection.m_WriteList as they have completed the request.
513518
/// </summary>
519+
[RequiresDynamicCode(WriteRequiresDynamicCode)]
514520
private sealed class HttpWebRequestArrayList : ArrayListWrapper
515521
{
516522
public HttpWebRequestArrayList(ArrayList list) : base(list)

src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Collections.Concurrent;
55
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
67
using System.Runtime.Versioning;
78
using System.Security;
89
using System.Threading;
@@ -249,6 +250,8 @@ private void RemoveInstrumentState(Instrument instrument, InstrumentState state)
249250
return instrumentState;
250251
}
251252

253+
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
254+
Justification = "MakeGenericType is creating instances over reference types that works fine in AOT.")]
252255
internal InstrumentState? BuildInstrumentState(Instrument instrument)
253256
{
254257
Func<Aggregator?>? createAggregatorFunc = GetAggregatorFactory(instrument);

0 commit comments

Comments
 (0)