From d6288c08e8ca100072bce5f79a0fe583fde7013a Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 28 Jul 2025 14:35:27 -0700 Subject: [PATCH 01/15] Import illink.targets for ref projects --- src/libraries/Directory.Build.targets | 2 +- src/libraries/System.CodeDom/Directory.Build.props | 1 + src/libraries/System.CodeDom/src/System.CodeDom.csproj | 1 - .../Directory.Build.props | 1 + .../src/System.ComponentModel.Composition.Registration.csproj | 1 - .../System.ComponentModel.Composition/Directory.Build.props | 1 + .../src/System.ComponentModel.Composition.csproj | 1 - .../Directory.Build.props | 2 ++ .../src/System.Configuration.ConfigurationManager.csproj | 2 -- src/libraries/System.Speech/Directory.Build.props | 1 + src/libraries/System.Speech/src/System.Speech.csproj | 1 - 11 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libraries/Directory.Build.targets b/src/libraries/Directory.Build.targets index 9998e676c5870e..44294aa74a7ac5 100644 --- a/src/libraries/Directory.Build.targets +++ b/src/libraries/Directory.Build.targets @@ -135,7 +135,7 @@ - + diff --git a/src/libraries/System.CodeDom/Directory.Build.props b/src/libraries/System.CodeDom/Directory.Build.props index 53773781258106..aad8d8747bf7bd 100644 --- a/src/libraries/System.CodeDom/Directory.Build.props +++ b/src/libraries/System.CodeDom/Directory.Build.props @@ -3,5 +3,6 @@ true browser;wasi;ios;tvos;maccatalyst + false \ No newline at end of file diff --git a/src/libraries/System.CodeDom/src/System.CodeDom.csproj b/src/libraries/System.CodeDom/src/System.CodeDom.csproj index 76ba0e1a9d3f64..3badaf158c75b3 100644 --- a/src/libraries/System.CodeDom/src/System.CodeDom.csproj +++ b/src/libraries/System.CodeDom/src/System.CodeDom.csproj @@ -3,7 +3,6 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) true $(DefineConstants);CODEDOM - false false true Provides types that can be used to model the structure of a source code document and to output source code for that model in C# or Visual Basic. diff --git a/src/libraries/System.ComponentModel.Composition.Registration/Directory.Build.props b/src/libraries/System.ComponentModel.Composition.Registration/Directory.Build.props index 798ccfd363e813..93a53093be2b00 100644 --- a/src/libraries/System.ComponentModel.Composition.Registration/Directory.Build.props +++ b/src/libraries/System.ComponentModel.Composition.Registration/Directory.Build.props @@ -2,5 +2,6 @@ ECMA + false diff --git a/src/libraries/System.ComponentModel.Composition.Registration/src/System.ComponentModel.Composition.Registration.csproj b/src/libraries/System.ComponentModel.Composition.Registration/src/System.ComponentModel.Composition.Registration.csproj index 530e2e89a7dd0e..b580a7534479c4 100644 --- a/src/libraries/System.ComponentModel.Composition.Registration/src/System.ComponentModel.Composition.Registration.csproj +++ b/src/libraries/System.ComponentModel.Composition.Registration/src/System.ComponentModel.Composition.Registration.csproj @@ -2,7 +2,6 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.1 - false false true true diff --git a/src/libraries/System.ComponentModel.Composition/Directory.Build.props b/src/libraries/System.ComponentModel.Composition/Directory.Build.props index 798ccfd363e813..93a53093be2b00 100644 --- a/src/libraries/System.ComponentModel.Composition/Directory.Build.props +++ b/src/libraries/System.ComponentModel.Composition/Directory.Build.props @@ -2,5 +2,6 @@ ECMA + false diff --git a/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj b/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj index 2f113db3e4cb5e..146b63ac69007f 100644 --- a/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj +++ b/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj @@ -2,7 +2,6 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0 - false false false true diff --git a/src/libraries/System.Configuration.ConfigurationManager/Directory.Build.props b/src/libraries/System.Configuration.ConfigurationManager/Directory.Build.props index 3a3d8f9832479f..bb0550b423f937 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/Directory.Build.props +++ b/src/libraries/System.Configuration.ConfigurationManager/Directory.Build.props @@ -3,5 +3,7 @@ true browser;wasi + + false \ No newline at end of file diff --git a/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj b/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj index 7b71ab3ed15111..9f55a50f14cc7b 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj +++ b/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj @@ -3,8 +3,6 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) $(NoWarn);CA2249 - - false false true false diff --git a/src/libraries/System.Speech/Directory.Build.props b/src/libraries/System.Speech/Directory.Build.props index d43c87c09cb684..6611932df4426a 100644 --- a/src/libraries/System.Speech/Directory.Build.props +++ b/src/libraries/System.Speech/Directory.Build.props @@ -3,5 +3,6 @@ MicrosoftShared windows + false \ No newline at end of file diff --git a/src/libraries/System.Speech/src/System.Speech.csproj b/src/libraries/System.Speech/src/System.Speech.csproj index f06f73fd105f8b..61723c53f0b3a5 100644 --- a/src/libraries/System.Speech/src/System.Speech.csproj +++ b/src/libraries/System.Speech/src/System.Speech.csproj @@ -15,7 +15,6 @@ $(NoWarn);CS1591 true - false true true true From 85c2f203df852d96f6485814b2f1f68c62657ad3 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 28 Jul 2025 14:58:46 -0700 Subject: [PATCH 02/15] Use live ref pack in analyzer tests --- .../ILLink.RoslynAnalyzer.Tests.csproj | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ILLink.RoslynAnalyzer.Tests.csproj b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ILLink.RoslynAnalyzer.Tests.csproj index 8323dd02f82afd..184616fc012c10 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ILLink.RoslynAnalyzer.Tests.csproj +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ILLink.RoslynAnalyzer.Tests.csproj @@ -37,16 +37,12 @@ - - - - - + + + From b5b09634ed4267372fa11e0150c82b806ae4d8dd Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 28 Jul 2025 16:44:51 -0700 Subject: [PATCH 03/15] Use IsAotCompatible for libraries --- src/libraries/Directory.Build.props | 4 ++-- src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj | 2 +- ....Extensions.DependencyInjection.Specification.Tests.csproj | 2 +- .../src/System.ComponentModel.Composition.csproj | 2 +- .../src/System.Composition.Hosting.csproj | 2 +- .../src/System.Composition.Runtime.csproj | 2 +- .../src/System.Composition.TypedParts.csproj | 2 +- .../src/System.Configuration.ConfigurationManager.csproj | 2 +- src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj | 2 +- src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj | 2 +- .../src/System.DirectoryServices.AccountManagement.csproj | 2 +- .../src/System.DirectoryServices.Protocols.csproj | 2 +- .../src/System.DirectoryServices.csproj | 2 +- .../src/System.Reflection.Context.csproj | 2 +- .../src/System.Reflection.MetadataLoadContext.csproj | 2 +- .../src/System.Resources.Extensions.csproj | 2 +- .../src/System.Runtime.InteropServices.JavaScript.csproj | 2 +- .../src/System.Runtime.Serialization.Schema.csproj | 2 +- .../src/System.ServiceModel.Syndication.csproj | 2 +- .../src/System.Windows.Extensions.csproj | 2 +- 20 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/libraries/Directory.Build.props b/src/libraries/Directory.Build.props index 77b995afb43bef..46bb87f01531d2 100644 --- a/src/libraries/Directory.Build.props +++ b/src/libraries/Directory.Build.props @@ -48,8 +48,8 @@ enable annotations - - true + + true diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj b/src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj index 20642af38a7a10..c0045d94b5e8fa 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj +++ b/src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj @@ -13,7 +13,7 @@ $(DefineConstants);ENABLECOMBINDER true $(DefineConstants);LEGACY_GETRESOURCESTRING_USER - true + true diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/Microsoft.Extensions.DependencyInjection.Specification.Tests.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/Microsoft.Extensions.DependencyInjection.Specification.Tests.csproj index 3257a2ecfc6f83..ba683d4ad02606 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/Microsoft.Extensions.DependencyInjection.Specification.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/Microsoft.Extensions.DependencyInjection.Specification.Tests.csproj @@ -7,7 +7,7 @@ true false false - false + false $(NoWarn);CA1852 $(NoWarn);1591 diff --git a/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj b/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj index 2f113db3e4cb5e..3a98cafcda232f 100644 --- a/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj +++ b/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj @@ -3,7 +3,7 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0 false - false + false false true true diff --git a/src/libraries/System.Composition.Hosting/src/System.Composition.Hosting.csproj b/src/libraries/System.Composition.Hosting/src/System.Composition.Hosting.csproj index 18d027e8ad14bb..c41c4876ca85ed 100644 --- a/src/libraries/System.Composition.Hosting/src/System.Composition.Hosting.csproj +++ b/src/libraries/System.Composition.Hosting/src/System.Composition.Hosting.csproj @@ -3,7 +3,7 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) false - false + false Microsoft false true diff --git a/src/libraries/System.Composition.Runtime/src/System.Composition.Runtime.csproj b/src/libraries/System.Composition.Runtime/src/System.Composition.Runtime.csproj index 93ef06e572afeb..78743812b829d3 100644 --- a/src/libraries/System.Composition.Runtime/src/System.Composition.Runtime.csproj +++ b/src/libraries/System.Composition.Runtime/src/System.Composition.Runtime.csproj @@ -3,7 +3,7 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) System.Composition - false + false Microsoft false true diff --git a/src/libraries/System.Composition.TypedParts/src/System.Composition.TypedParts.csproj b/src/libraries/System.Composition.TypedParts/src/System.Composition.TypedParts.csproj index 3a2874d9d3f0b4..318ec32b398045 100644 --- a/src/libraries/System.Composition.TypedParts/src/System.Composition.TypedParts.csproj +++ b/src/libraries/System.Composition.TypedParts/src/System.Composition.TypedParts.csproj @@ -4,7 +4,7 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) System.Composition false - false + false Microsoft false true diff --git a/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj b/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj index 7b71ab3ed15111..5bb963d2e8f8c7 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj +++ b/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj @@ -5,7 +5,7 @@ $(NoWarn);CA2249 false - false + false true false true diff --git a/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj b/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj index 13e559dbb3c3dc..413cc706c2b338 100644 --- a/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj +++ b/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj @@ -5,7 +5,7 @@ $(TargetFrameworks);$(NetCoreAppPrevious)-windows;$(NetCoreAppPrevious)-unix;$(NetCoreAppPrevious) true $(NoWarn);CA2249;CA1838 - false + false false true Provides a collection of classes used to access an ODBC data source in the managed space diff --git a/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj b/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj index d366c5cad37b04..9a60518e629494 100644 --- a/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj +++ b/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj @@ -8,7 +8,7 @@ $(NoWarn);CA2249 $(NoWarn);SYSLIB0004 - false + false false true Provides a collection of classes for OLEDB. diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/System.DirectoryServices.AccountManagement.csproj b/src/libraries/System.DirectoryServices.AccountManagement/src/System.DirectoryServices.AccountManagement.csproj index a92c51f7b9aa4a..f206c88428b749 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/src/System.DirectoryServices.AccountManagement.csproj +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/System.DirectoryServices.AccountManagement.csproj @@ -7,7 +7,7 @@ true $(NoWarn);CA2249 $(NoWarn);IDE0059;IDE0060;CA1822;CA1859 - false + false false true true diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj index a14b7fa4d14b8d..740924b82f8fa0 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj +++ b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj @@ -12,7 +12,7 @@ Provides the methods defined in the Lightweight Directory Access Protocol (LDAP) version 3 (V3) and Directory Services Markup Language (DSML) version 2.0 (V2) standards. $(NoWarn);CS3016 - false + false disable diff --git a/src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj b/src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj index 845f7627ca3ee3..d759905d94c0fa 100644 --- a/src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj +++ b/src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj @@ -6,7 +6,7 @@ true true $(NoWarn);IDE0059;IDE0060;CA1822;CA1865 - false + false false true true diff --git a/src/libraries/System.Reflection.Context/src/System.Reflection.Context.csproj b/src/libraries/System.Reflection.Context/src/System.Reflection.Context.csproj index bceb051a5fe15b..7522294cdfbdb9 100644 --- a/src/libraries/System.Reflection.Context/src/System.Reflection.Context.csproj +++ b/src/libraries/System.Reflection.Context/src/System.Reflection.Context.csproj @@ -2,7 +2,7 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.1;netstandard2.0 - false + false false true true diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj index 524c33fc8d2ac7..461be58422d22d 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj @@ -4,7 +4,7 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) System.Reflection true - false + false false true $(NoWarn);CA1865 diff --git a/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj b/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj index f8838d6b45b83f..947932941ffc44 100644 --- a/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj +++ b/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj @@ -4,7 +4,7 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) true $(DefineConstants);RESOURCES_EXTENSIONS - false + false true false true diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj index 4b637cee5f1743..551cf32384d450 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj @@ -3,7 +3,7 @@ $(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent) true - false + false false diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj index 7c65f69b104fb1..1f50e28449bf3e 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj @@ -2,7 +2,7 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum) - false + false true Provides support for importing and exporting xsd schemas for DataContractSerializer. diff --git a/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj b/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj index 29a05a68ef6492..c01a599cc31f2d 100644 --- a/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj +++ b/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj @@ -2,7 +2,7 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) - false + false true false true diff --git a/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj b/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj index 609bc2999afc44..2925f54d005adb 100644 --- a/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj +++ b/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj @@ -4,7 +4,7 @@ $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent);$(NetCoreAppMinimum)-windows;$(NetCoreAppMinimum) $(TargetFrameworks);$(NetCoreAppPrevious)-windows;$(NetCoreAppPrevious) true - false + false false true Provides miscellaneous Windows-specific types From 7c04ce7af264611395b937f29a672a11b2ab1285 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 28 Jul 2025 16:02:29 -0700 Subject: [PATCH 04/15] Add warning for non-trimmable refs --- .../MSBuildPropertyOptionNames.cs | 1 + .../RequiresAnalyzerBase.cs | 4 + .../RequiresUnreferencedCodeAnalyzer.cs | 37 +++++- .../illink/src/ILLink.Shared/DiagnosticId.cs | 1 + .../src/ILLink.Shared/SharedStrings.resx | 6 + .../ReferenceTrimCompatibilityTests.cs | 106 ++++++++++++++++++ 6 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceTrimCompatibilityTests.cs diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/MSBuildPropertyOptionNames.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/MSBuildPropertyOptionNames.cs index e86d0b9d8486e2..ecbe1862caa55f 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/MSBuildPropertyOptionNames.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/MSBuildPropertyOptionNames.cs @@ -9,5 +9,6 @@ public static class MSBuildPropertyOptionNames public const string IncludeAllContentForSelfExtract = nameof(IncludeAllContentForSelfExtract); public const string EnableTrimAnalyzer = nameof(EnableTrimAnalyzer); public const string EnableAotAnalyzer = nameof(EnableAotAnalyzer); + public const string VerifyReferenceTrimCompatibility = nameof(VerifyReferenceTrimCompatibility); } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs index 444c0ff3ff7a0f..284e403f158e9c 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs @@ -36,6 +36,7 @@ public abstract class RequiresAnalyzerBase : DiagnosticAnalyzer private protected virtual ImmutableArray<(Action Action, SyntaxKind[] SyntaxKind)> ExtraSyntaxNodeActions { get; } = ImmutableArray<(Action Action, SyntaxKind[] SyntaxKind)>.Empty; private protected virtual ImmutableArray<(Action Action, SymbolKind[] SymbolKind)> ExtraSymbolActions { get; } = ImmutableArray<(Action Action, SymbolKind[] SymbolKind)>.Empty; + private protected virtual ImmutableArray> ExtraCompilationActions { get; } = ImmutableArray>.Empty; public override void Initialize(AnalysisContext context) { @@ -165,6 +166,9 @@ void CheckMatchingAttributesInInterfaces( } } }); + + foreach (var extraCompilationAction in ExtraCompilationActions) + context.RegisterCompilationAction(extraCompilationAction); } internal void CheckAndCreateRequiresDiagnostic( diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs index be50cb92f5a66b..ad92323a8ecaac 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs @@ -26,6 +26,7 @@ public sealed class RequiresUnreferencedCodeAnalyzer : RequiresAnalyzerBase private static readonly DiagnosticDescriptor s_requiresUnreferencedCodeOnEntryPoint = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.RequiresUnreferencedCodeOnEntryPoint); private static readonly DiagnosticDescriptor s_typeDerivesFromRucClassRule = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.RequiresUnreferencedCodeOnBaseClass); + private static readonly DiagnosticDescriptor s_referenceNotMarkedIsTrimmableRule = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.ReferenceNotMarkedIsTrimmable); private Action typeDerivesFromRucBase { @@ -50,7 +51,7 @@ private Action typeDerivesFromRucBase } public override ImmutableArray SupportedDiagnostics => - ImmutableArray.Create(s_makeGenericMethodRule, s_makeGenericTypeRule, s_requiresUnreferencedCodeRule, s_requiresUnreferencedCodeAttributeMismatch, s_typeDerivesFromRucClassRule, s_requiresUnreferencedCodeOnStaticCtor, s_requiresUnreferencedCodeOnEntryPoint); + ImmutableArray.Create(s_makeGenericMethodRule, s_makeGenericTypeRule, s_requiresUnreferencedCodeRule, s_requiresUnreferencedCodeAttributeMismatch, s_typeDerivesFromRucClassRule, s_requiresUnreferencedCodeOnStaticCtor, s_requiresUnreferencedCodeOnEntryPoint, s_referenceNotMarkedIsTrimmableRule); private protected override string RequiresAttributeName => RequiresUnreferencedCodeAttribute; @@ -71,6 +72,37 @@ private Action typeDerivesFromRucBase internal override bool IsAnalyzerEnabled(AnalyzerOptions options) => options.IsMSBuildPropertyValueTrue(MSBuildPropertyOptionNames.EnableTrimAnalyzer); + private void CheckReferencedAssembliesForTrimmable(CompilationAnalysisContext context) + { + var options = context.Options; + if (!IsAnalyzerEnabled(options)) + return; + + if (!options.IsMSBuildPropertyValueTrue(MSBuildPropertyOptionNames.VerifyReferenceTrimCompatibility)) + return; + + foreach (var reference in context.Compilation.References) + { + var refAssembly = context.Compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol; + if (refAssembly is null) + continue; + + var isTrimmable = refAssembly.GetAttributes().FirstOrDefault(attr => + attr.AttributeClass?.Name == "AssemblyMetadataAttribute" && + attr.ConstructorArguments.Length == 2 && + attr.ConstructorArguments[0].Value?.ToString() == "IsTrimmable" && + string.Equals(attr.ConstructorArguments[1].Value?.ToString(), "True", StringComparison.OrdinalIgnoreCase)); + + if (isTrimmable is null) + { + var diag = Diagnostic.Create(s_referenceNotMarkedIsTrimmableRule, + Location.None, + refAssembly.Name); + context.ReportDiagnostic(diag); + } + } + } + private protected override bool IsRequiresCheck(IPropertySymbol propertySymbol, Compilation compilation) { // "IsUnreferencedCodeSupported" is treated as a requires check for testing purposes only, and @@ -102,6 +134,9 @@ protected override bool CreateSpecialIncompatibleMembersDiagnostic( private protected override ImmutableArray<(Action Action, SymbolKind[] SymbolKind)> ExtraSymbolActions => ImmutableArray.Create<(Action Action, SymbolKind[] SymbolKind)>((typeDerivesFromRucBase, new SymbolKind[] { SymbolKind.NamedType })); + private protected override ImmutableArray> ExtraCompilationActions => + ImmutableArray.Create>(CheckReferencedAssembliesForTrimmable); + protected override bool VerifyAttributeArguments(AttributeData attribute) => RequiresUnreferencedCodeUtils.VerifyRequiresUnreferencedCodeAttributeArguments(attribute); diff --git a/src/tools/illink/src/ILLink.Shared/DiagnosticId.cs b/src/tools/illink/src/ILLink.Shared/DiagnosticId.cs index 68f96275ff718c..0f7269ed8acfb0 100644 --- a/src/tools/illink/src/ILLink.Shared/DiagnosticId.cs +++ b/src/tools/illink/src/ILLink.Shared/DiagnosticId.cs @@ -189,6 +189,7 @@ public enum DiagnosticId TypeNameIsNotAssemblyQualified = 2122, RequiresUnreferencedCodeOnEntryPoint = 2123, TypeMapGroupTypeCannotBeStaticallyDetermined = 2124, + ReferenceNotMarkedIsTrimmable = 2125, _EndTrimAnalysisWarningsSentinel, // Single-file diagnostic ids. diff --git a/src/tools/illink/src/ILLink.Shared/SharedStrings.resx b/src/tools/illink/src/ILLink.Shared/SharedStrings.resx index 40c921ca706cde..817696f7747971 100644 --- a/src/tools/illink/src/ILLink.Shared/SharedStrings.resx +++ b/src/tools/illink/src/ILLink.Shared/SharedStrings.resx @@ -1239,4 +1239,10 @@ Type name is not assembly qualified. + + Referenced assembly is not marked as trimmable. + + + Referenced assembly '{0}' is not marked with AssemblyMetadataAttribute IsTrimmable=True and may not be compatible with trimming. + diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceTrimCompatibilityTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceTrimCompatibilityTests.cs new file mode 100644 index 00000000000000..914e36137a3f4e --- /dev/null +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceTrimCompatibilityTests.cs @@ -0,0 +1,106 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading.Tasks; +using ILLink.Shared; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; +using Xunit; +using System.IO; +using VerifyCS = ILLink.RoslynAnalyzer.Tests.CSharpCodeFixVerifier< + ILLink.RoslynAnalyzer.RequiresUnreferencedCodeAnalyzer, + ILLink.CodeFix.RequiresUnreferencedCodeCodeFixProvider>; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace ILLink.RoslynAnalyzer.Tests +{ + public class ReferenceTrimCompatibilityTests + { + private static VerifyCS.Test CreateTestWithReference(string mainSource, string referenceSource) + { + var referencedMetadata = CreateReferencedMetadata(referenceSource); + var test = new VerifyCS.Test + { + TestCode = mainSource + }; + test.SolutionTransforms.Add((solution, projectId) => + { + var project = solution.GetProject(projectId); + if (project is null) + return solution; + project = project.AddMetadataReference(referencedMetadata); + return project.Solution; + }); + return test; + + static MetadataReference CreateReferencedMetadata(string referencedSource) + { + var refs = SourceGenerators.Tests.LiveReferencePack.GetMetadataReferences(); + var referencedCompilation = CSharpCompilation.Create( + "ReferencedAssembly", + new[] { SyntaxFactory.ParseSyntaxTree(referencedSource) }, + refs, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + var referencedImage = new MemoryStream(); + referencedCompilation.Emit(referencedImage); + referencedImage.Position = 0; + return MetadataReference.CreateFromStream(referencedImage); + } + } + + [Fact] + public async Task EmitsWarningForReferenceWithoutIsTrimmable_WhenPropertyEnabled() + { + var referencedSource = "public class ReferencedClass { }"; + var testSource = "public class MainClass { ReferencedClass c; }"; + + var test = CreateTestWithReference(testSource, referencedSource); + test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", Microsoft.CodeAnalysis.Text.SourceText.From($""" + is_global = true + build_property.{ILLink.RoslynAnalyzer.MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true + build_property.{ILLink.RoslynAnalyzer.MSBuildPropertyOptionNames.VerifyReferenceTrimCompatibility} = true + """))); + test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DiagnosticId.ReferenceNotMarkedIsTrimmable).WithArguments("ReferencedAssembly")); + await test.RunAsync(); + } + + [Fact] + public async Task DoesNotEmitWarning_WhenVerifyReferenceTrimCompatibilityDisabled() + { + var referencedSource = "public class ReferencedClass { }"; + var testSource = "public class MainClass { ReferencedClass c; }"; + + var test = CreateTestWithReference(testSource, referencedSource); + test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", Microsoft.CodeAnalysis.Text.SourceText.From($""" + is_global = true + build_property.{ILLink.RoslynAnalyzer.MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true + build_property.{ILLink.RoslynAnalyzer.MSBuildPropertyOptionNames.VerifyReferenceTrimCompatibility} = false + """))); + + await test.RunAsync(); + } + + [Fact] + public async Task DoesNotEmitWarning_WhenReferenceMarkedIsTrimmable() + { + var referencedSource = """ + [assembly: System.Reflection.AssemblyMetadata("IsTrimmable", "True")] + public class ReferencedClass { } + """; + var testSource = "public class MainClass { ReferencedClass c; }"; + + var test = CreateTestWithReference(testSource, referencedSource); + test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", Microsoft.CodeAnalysis.Text.SourceText.From($""" + is_global = true + build_property.{ILLink.RoslynAnalyzer.MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true + build_property.{ILLink.RoslynAnalyzer.MSBuildPropertyOptionNames.VerifyReferenceTrimCompatibility} = true + """))); + + await test.RunAsync(); + } + } +} From 16bae65d28edfdcdb9b43f2d9e2dc2f1783c44ae Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 29 Jul 2025 09:48:04 -0700 Subject: [PATCH 05/15] Add warning for non-AOT-compatible refs --- .../MSBuildPropertyOptionNames.cs | 1 + .../RequiresDynamicCodeAnalyzer.cs | 37 ++++++++- .../illink/src/ILLink.Shared/DiagnosticId.cs | 1 + .../src/ILLink.Shared/SharedStrings.resx | 6 ++ .../ReferenceAotCompatibilityTests.cs | 76 +++++++++++++++++++ .../ReferenceCompatibilityTestUtils.cs | 55 ++++++++++++++ .../ReferenceTrimCompatibilityTests.cs | 42 ++-------- 7 files changed, 182 insertions(+), 36 deletions(-) create mode 100644 src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceAotCompatibilityTests.cs create mode 100644 src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceCompatibilityTestUtils.cs diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/MSBuildPropertyOptionNames.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/MSBuildPropertyOptionNames.cs index ecbe1862caa55f..51a5645b4318c6 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/MSBuildPropertyOptionNames.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/MSBuildPropertyOptionNames.cs @@ -9,6 +9,7 @@ public static class MSBuildPropertyOptionNames public const string IncludeAllContentForSelfExtract = nameof(IncludeAllContentForSelfExtract); public const string EnableTrimAnalyzer = nameof(EnableTrimAnalyzer); public const string EnableAotAnalyzer = nameof(EnableAotAnalyzer); + public const string VerifyReferenceAotCompatibility = nameof(VerifyReferenceAotCompatibility); public const string VerifyReferenceTrimCompatibility = nameof(VerifyReferenceTrimCompatibility); } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs index 8e089da80d58ea..9593a47a0ac6c8 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs @@ -23,9 +23,41 @@ public sealed class RequiresDynamicCodeAnalyzer : RequiresAnalyzerBase private static readonly DiagnosticDescriptor s_requiresDynamicCodeOnEntryPoint = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.RequiresDynamicCodeOnEntryPoint); private static readonly DiagnosticDescriptor s_requiresDynamicCodeRule = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.RequiresDynamicCode); private static readonly DiagnosticDescriptor s_requiresDynamicCodeAttributeMismatch = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.RequiresDynamicCodeAttributeMismatch); + private static readonly DiagnosticDescriptor s_referenceNotMarkedIsAotCompatibleRule = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.ReferenceNotMarkedIsAotCompatible); public override ImmutableArray SupportedDiagnostics => - ImmutableArray.Create(s_requiresDynamicCodeRule, s_requiresDynamicCodeAttributeMismatch, s_requiresDynamicCodeOnStaticCtor, s_requiresDynamicCodeOnEntryPoint); + ImmutableArray.Create(s_requiresDynamicCodeRule, s_requiresDynamicCodeAttributeMismatch, s_requiresDynamicCodeOnStaticCtor, s_requiresDynamicCodeOnEntryPoint, s_referenceNotMarkedIsAotCompatibleRule); + + private void CheckReferencedAssembliesForAotCompatible(CompilationAnalysisContext context) + { + var options = context.Options; + if (!IsAnalyzerEnabled(options)) + return; + + if (!options.IsMSBuildPropertyValueTrue(MSBuildPropertyOptionNames.VerifyReferenceAotCompatibility)) + return; + + foreach (var reference in context.Compilation.References) + { + var refAssembly = context.Compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol; + if (refAssembly is null) + continue; + + var isAotCompatible = refAssembly.GetAttributes().FirstOrDefault(attr => + attr.AttributeClass?.Name == "AssemblyMetadataAttribute" && + attr.ConstructorArguments.Length == 2 && + attr.ConstructorArguments[0].Value?.ToString() == "IsAotCompatible" && + string.Equals(attr.ConstructorArguments[1].Value?.ToString(), "True", StringComparison.OrdinalIgnoreCase)); + + if (isAotCompatible is null) + { + var diag = Diagnostic.Create(s_referenceNotMarkedIsAotCompatibleRule, + Location.None, + refAssembly.Name); + context.ReportDiagnostic(diag); + } + } + } private protected override string RequiresAttributeName => RequiresDynamicCodeAttribute; @@ -163,6 +195,9 @@ private protected override bool IsRequiresCheck(IPropertySymbol propertySymbol, return SymbolEqualityComparer.Default.Equals(propertySymbol, isDynamicCodeSupportedProperty); } + private protected override ImmutableArray> ExtraCompilationActions => + ImmutableArray.Create>(CheckReferencedAssembliesForAotCompatible); + protected override bool VerifyAttributeArguments(AttributeData attribute) => attribute.ConstructorArguments.Length >= 1 && attribute.ConstructorArguments is [{ Type.SpecialType: SpecialType.System_String }, ..]; diff --git a/src/tools/illink/src/ILLink.Shared/DiagnosticId.cs b/src/tools/illink/src/ILLink.Shared/DiagnosticId.cs index 0f7269ed8acfb0..5347575e2fe42f 100644 --- a/src/tools/illink/src/ILLink.Shared/DiagnosticId.cs +++ b/src/tools/illink/src/ILLink.Shared/DiagnosticId.cs @@ -209,6 +209,7 @@ public enum DiagnosticId CorrectnessOfAbstractDelegatesCannotBeGuaranteed = 3055, RequiresDynamicCodeOnStaticConstructor = 3056, RequiresDynamicCodeOnEntryPoint = 3057, + ReferenceNotMarkedIsAotCompatible = 3058, _EndAotAnalysisWarningsSentinel, // Feature guard diagnostic ids. diff --git a/src/tools/illink/src/ILLink.Shared/SharedStrings.resx b/src/tools/illink/src/ILLink.Shared/SharedStrings.resx index 817696f7747971..f9832c591d102a 100644 --- a/src/tools/illink/src/ILLink.Shared/SharedStrings.resx +++ b/src/tools/illink/src/ILLink.Shared/SharedStrings.resx @@ -1245,4 +1245,10 @@ Referenced assembly '{0}' is not marked with AssemblyMetadataAttribute IsTrimmable=True and may not be compatible with trimming. + + Referenced assembly is not marked as AOT-compatible. + + + Referenced assembly '{0}' is not marked with AssemblyMetadataAttribute IsAotCompatible=True and may not be compatible with AOT. + diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceAotCompatibilityTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceAotCompatibilityTests.cs new file mode 100644 index 00000000000000..e52afef7b692d2 --- /dev/null +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceAotCompatibilityTests.cs @@ -0,0 +1,76 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading.Tasks; +using ILLink.Shared; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; +using Xunit; +using System.IO; +using VerifyCS = ILLink.RoslynAnalyzer.Tests.CSharpCodeFixVerifier< + ILLink.RoslynAnalyzer.RequiresDynamicCodeAnalyzer, + ILLink.CodeFix.RequiresDynamicCodeCodeFixProvider>; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using ILLink.CodeFix; + +namespace ILLink.RoslynAnalyzer.Tests +{ + public class ReferenceAotCompatibilityTests + { + [Fact] + public async Task EmitsWarningForReferenceWithoutIsAotCompatible_WhenPropertyEnabled() + { + var referencedSource = "public class ReferencedClass { }"; + var testSource = "public class MainClass { ReferencedClass c; }"; + + var test = ReferenceCompatibilityTestUtils.CreateTestWithReference( + testSource, referencedSource); + test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", Microsoft.CodeAnalysis.Text.SourceText.From($""" + is_global = true + build_property.{ILLink.RoslynAnalyzer.MSBuildPropertyOptionNames.EnableAotAnalyzer} = true + build_property.VerifyReferenceAotCompatibility = true + """))); + test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DiagnosticId.ReferenceNotMarkedIsAotCompatible).WithArguments("ReferencedAssembly")); + await test.RunAsync(); + } + + [Fact] + public async Task DoesNotEmitWarning_WhenVerifyReferenceAotCompatibilityDisabled() + { + var referencedSource = "public class ReferencedClass { }"; + var testSource = "public class MainClass { ReferencedClass c; }"; + + var test = ReferenceCompatibilityTestUtils.CreateTestWithReference( + testSource, referencedSource); + test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", Microsoft.CodeAnalysis.Text.SourceText.From($""" + is_global = true + build_property.{ILLink.RoslynAnalyzer.MSBuildPropertyOptionNames.EnableAotAnalyzer} = true + build_property.VerifyReferenceAotCompatibility = false + """))); + await test.RunAsync(); + } + + [Fact] + public async Task DoesNotEmitWarning_WhenReferenceMarkedIsAotCompatible() + { + var referencedSource = """ + [assembly: System.Reflection.AssemblyMetadata("IsAotCompatible", "True")] + public class ReferencedClass { } + """; + var testSource = "public class MainClass { ReferencedClass c; }"; + + var test = ReferenceCompatibilityTestUtils.CreateTestWithReference( + testSource, referencedSource); + test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", Microsoft.CodeAnalysis.Text.SourceText.From($""" + is_global = true + build_property.{ILLink.RoslynAnalyzer.MSBuildPropertyOptionNames.EnableAotAnalyzer} = true + build_property.VerifyReferenceAotCompatibility = true + """))); + await test.RunAsync(); + } + } +} diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceCompatibilityTestUtils.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceCompatibilityTestUtils.cs new file mode 100644 index 00000000000000..a5169775cc45bc --- /dev/null +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceCompatibilityTestUtils.cs @@ -0,0 +1,55 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading.Tasks; +using ILLink.Shared; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using Xunit; +using System.IO; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace ILLink.RoslynAnalyzer.Tests +{ + public class ReferenceCompatibilityTestUtils + { + public static CSharpCodeFixVerifier.Test CreateTestWithReference(string mainSource, string referenceSource) + where TAnalyzer : DiagnosticAnalyzer, new() + where TCodeFix : Microsoft.CodeAnalysis.CodeFixes.CodeFixProvider, new() + { + var referencedMetadata = CreateReferencedMetadata(referenceSource); + var test = new CSharpCodeFixVerifier.Test + { + TestCode = mainSource + }; + test.SolutionTransforms.Add((solution, projectId) => + { + var project = solution.GetProject(projectId); + if (project is null) + return solution; + project = project.AddMetadataReference(referencedMetadata); + return project.Solution; + }); + return test; + + static MetadataReference CreateReferencedMetadata(string referencedSource) + { + var refs = SourceGenerators.Tests.LiveReferencePack.GetMetadataReferences(); + var referencedCompilation = CSharpCompilation.Create( + "ReferencedAssembly", + new[] { SyntaxFactory.ParseSyntaxTree(referencedSource) }, + refs, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + var referencedImage = new MemoryStream(); + referencedCompilation.Emit(referencedImage); + referencedImage.Position = 0; + return MetadataReference.CreateFromStream(referencedImage); + } + } + } +} diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceTrimCompatibilityTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceTrimCompatibilityTests.cs index 914e36137a3f4e..0a0951e51afc77 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceTrimCompatibilityTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReferenceTrimCompatibilityTests.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Testing; using Xunit; using System.IO; +using ILLink.CodeFix; using VerifyCS = ILLink.RoslynAnalyzer.Tests.CSharpCodeFixVerifier< ILLink.RoslynAnalyzer.RequiresUnreferencedCodeAnalyzer, ILLink.CodeFix.RequiresUnreferencedCodeCodeFixProvider>; @@ -20,45 +21,14 @@ namespace ILLink.RoslynAnalyzer.Tests { public class ReferenceTrimCompatibilityTests { - private static VerifyCS.Test CreateTestWithReference(string mainSource, string referenceSource) - { - var referencedMetadata = CreateReferencedMetadata(referenceSource); - var test = new VerifyCS.Test - { - TestCode = mainSource - }; - test.SolutionTransforms.Add((solution, projectId) => - { - var project = solution.GetProject(projectId); - if (project is null) - return solution; - project = project.AddMetadataReference(referencedMetadata); - return project.Solution; - }); - return test; - - static MetadataReference CreateReferencedMetadata(string referencedSource) - { - var refs = SourceGenerators.Tests.LiveReferencePack.GetMetadataReferences(); - var referencedCompilation = CSharpCompilation.Create( - "ReferencedAssembly", - new[] { SyntaxFactory.ParseSyntaxTree(referencedSource) }, - refs, - new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); - var referencedImage = new MemoryStream(); - referencedCompilation.Emit(referencedImage); - referencedImage.Position = 0; - return MetadataReference.CreateFromStream(referencedImage); - } - } - [Fact] public async Task EmitsWarningForReferenceWithoutIsTrimmable_WhenPropertyEnabled() { var referencedSource = "public class ReferencedClass { }"; var testSource = "public class MainClass { ReferencedClass c; }"; - var test = CreateTestWithReference(testSource, referencedSource); + var test = ReferenceCompatibilityTestUtils.CreateTestWithReference( + testSource, referencedSource); test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", Microsoft.CodeAnalysis.Text.SourceText.From($""" is_global = true build_property.{ILLink.RoslynAnalyzer.MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true @@ -74,7 +44,8 @@ public async Task DoesNotEmitWarning_WhenVerifyReferenceTrimCompatibilityDisable var referencedSource = "public class ReferencedClass { }"; var testSource = "public class MainClass { ReferencedClass c; }"; - var test = CreateTestWithReference(testSource, referencedSource); + var test = ReferenceCompatibilityTestUtils.CreateTestWithReference( + testSource, referencedSource); test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", Microsoft.CodeAnalysis.Text.SourceText.From($""" is_global = true build_property.{ILLink.RoslynAnalyzer.MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true @@ -93,7 +64,8 @@ public class ReferencedClass { } """; var testSource = "public class MainClass { ReferencedClass c; }"; - var test = CreateTestWithReference(testSource, referencedSource); + var test = ReferenceCompatibilityTestUtils.CreateTestWithReference( + testSource, referencedSource); test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", Microsoft.CodeAnalysis.Text.SourceText.From($""" is_global = true build_property.{ILLink.RoslynAnalyzer.MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true From 879f9904d25a2b6f01d7d2d8f2cf7922e5b75cb3 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 29 Jul 2025 10:07:46 -0700 Subject: [PATCH 06/15] Share IsAotCompatible between src/ref --- .../System.ComponentModel.Composition/Directory.Build.props | 1 + .../src/System.ComponentModel.Composition.csproj | 1 - .../Directory.Build.props | 1 + .../src/System.Configuration.ConfigurationManager.csproj | 1 - src/libraries/System.Data.Odbc/Directory.Build.props | 1 + src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj | 1 - src/libraries/System.Data.OleDb/Directory.Build.props | 1 + .../System.Data.OleDb/src/System.Data.OleDb.csproj | 1 - .../Directory.Build.props | 1 + .../src/System.DirectoryServices.AccountManagement.csproj | 1 - .../Directory.Build.props | 1 + .../src/System.DirectoryServices.Protocols.csproj | 1 - .../System.DirectoryServices/Directory.Build.props | 1 + .../src/System.DirectoryServices.csproj | 1 - .../System.Reflection.Context/Directory.Build.props | 1 + .../src/System.Reflection.Context.csproj | 1 - .../Directory.Build.props | 6 ++++++ .../src/System.Reflection.MetadataLoadContext.csproj | 1 - .../System.Resources.Extensions/Directory.Build.props | 6 ++++++ .../src/System.Resources.Extensions.csproj | 1 - .../Directory.Build.props | 1 + .../src/System.Runtime.InteropServices.JavaScript.csproj | 1 - .../Directory.Build.props | 1 + .../src/System.Runtime.Serialization.Schema.csproj | 1 - .../System.ServiceModel.Syndication/Directory.Build.props | 6 ++++++ .../src/System.ServiceModel.Syndication.csproj | 1 - .../System.Windows.Extensions/Directory.Build.props | 1 + .../src/System.Windows.Extensions.csproj | 1 - 28 files changed, 29 insertions(+), 14 deletions(-) create mode 100644 src/libraries/System.Reflection.MetadataLoadContext/Directory.Build.props create mode 100644 src/libraries/System.Resources.Extensions/Directory.Build.props create mode 100644 src/libraries/System.ServiceModel.Syndication/Directory.Build.props diff --git a/src/libraries/System.ComponentModel.Composition/Directory.Build.props b/src/libraries/System.ComponentModel.Composition/Directory.Build.props index 93a53093be2b00..db56d69d6c8b7d 100644 --- a/src/libraries/System.ComponentModel.Composition/Directory.Build.props +++ b/src/libraries/System.ComponentModel.Composition/Directory.Build.props @@ -3,5 +3,6 @@ ECMA false + false diff --git a/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj b/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj index bf33fd2291fe2d..9172222222e872 100644 --- a/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj +++ b/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj @@ -2,7 +2,6 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0 - false false true true diff --git a/src/libraries/System.Configuration.ConfigurationManager/Directory.Build.props b/src/libraries/System.Configuration.ConfigurationManager/Directory.Build.props index bb0550b423f937..c23e70d0e2d061 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/Directory.Build.props +++ b/src/libraries/System.Configuration.ConfigurationManager/Directory.Build.props @@ -5,5 +5,6 @@ browser;wasi false + false \ No newline at end of file diff --git a/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj b/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj index e89fa183178752..9e1859f7e80ef9 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj +++ b/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj @@ -3,7 +3,6 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) $(NoWarn);CA2249 - false true false true diff --git a/src/libraries/System.Data.Odbc/Directory.Build.props b/src/libraries/System.Data.Odbc/Directory.Build.props index 3a3d8f9832479f..6e1b965d020cfa 100644 --- a/src/libraries/System.Data.Odbc/Directory.Build.props +++ b/src/libraries/System.Data.Odbc/Directory.Build.props @@ -3,5 +3,6 @@ true browser;wasi + false \ No newline at end of file diff --git a/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj b/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj index 413cc706c2b338..34e55db4831286 100644 --- a/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj +++ b/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj @@ -5,7 +5,6 @@ $(TargetFrameworks);$(NetCoreAppPrevious)-windows;$(NetCoreAppPrevious)-unix;$(NetCoreAppPrevious) true $(NoWarn);CA2249;CA1838 - false false true Provides a collection of classes used to access an ODBC data source in the managed space diff --git a/src/libraries/System.Data.OleDb/Directory.Build.props b/src/libraries/System.Data.OleDb/Directory.Build.props index 6c6a6c1b425414..5f2e969d9f28ca 100644 --- a/src/libraries/System.Data.OleDb/Directory.Build.props +++ b/src/libraries/System.Data.OleDb/Directory.Build.props @@ -2,5 +2,6 @@ windows + false \ No newline at end of file diff --git a/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj b/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj index 9a60518e629494..5e454a02f23734 100644 --- a/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj +++ b/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj @@ -8,7 +8,6 @@ $(NoWarn);CA2249 $(NoWarn);SYSLIB0004 - false false true Provides a collection of classes for OLEDB. diff --git a/src/libraries/System.DirectoryServices.AccountManagement/Directory.Build.props b/src/libraries/System.DirectoryServices.AccountManagement/Directory.Build.props index de81d80c303d7d..395c1d3ae6ba72 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/Directory.Build.props +++ b/src/libraries/System.DirectoryServices.AccountManagement/Directory.Build.props @@ -3,5 +3,6 @@ ECMA windows + false \ No newline at end of file diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/System.DirectoryServices.AccountManagement.csproj b/src/libraries/System.DirectoryServices.AccountManagement/src/System.DirectoryServices.AccountManagement.csproj index f206c88428b749..2d658680497482 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/src/System.DirectoryServices.AccountManagement.csproj +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/System.DirectoryServices.AccountManagement.csproj @@ -7,7 +7,6 @@ true $(NoWarn);CA2249 $(NoWarn);IDE0059;IDE0060;CA1822;CA1859 - false false true true diff --git a/src/libraries/System.DirectoryServices.Protocols/Directory.Build.props b/src/libraries/System.DirectoryServices.Protocols/Directory.Build.props index 831e8089e2459c..ec9059203e7dd9 100644 --- a/src/libraries/System.DirectoryServices.Protocols/Directory.Build.props +++ b/src/libraries/System.DirectoryServices.Protocols/Directory.Build.props @@ -4,5 +4,6 @@ Microsoft true browser;android;ios;tvos + false diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj index 740924b82f8fa0..682599efc835d3 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj +++ b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj @@ -12,7 +12,6 @@ Provides the methods defined in the Lightweight Directory Access Protocol (LDAP) version 3 (V3) and Directory Services Markup Language (DSML) version 2.0 (V2) standards. $(NoWarn);CS3016 - false disable diff --git a/src/libraries/System.DirectoryServices/Directory.Build.props b/src/libraries/System.DirectoryServices/Directory.Build.props index 709a22a7537088..0bcccb8bb216a0 100644 --- a/src/libraries/System.DirectoryServices/Directory.Build.props +++ b/src/libraries/System.DirectoryServices/Directory.Build.props @@ -3,5 +3,6 @@ Microsoft windows + false \ No newline at end of file diff --git a/src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj b/src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj index d759905d94c0fa..20f66fb30edb6f 100644 --- a/src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj +++ b/src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj @@ -6,7 +6,6 @@ true true $(NoWarn);IDE0059;IDE0060;CA1822;CA1865 - false false true true diff --git a/src/libraries/System.Reflection.Context/Directory.Build.props b/src/libraries/System.Reflection.Context/Directory.Build.props index 798ccfd363e813..fc1d9fb498d24c 100644 --- a/src/libraries/System.Reflection.Context/Directory.Build.props +++ b/src/libraries/System.Reflection.Context/Directory.Build.props @@ -2,5 +2,6 @@ ECMA + false diff --git a/src/libraries/System.Reflection.Context/src/System.Reflection.Context.csproj b/src/libraries/System.Reflection.Context/src/System.Reflection.Context.csproj index 7522294cdfbdb9..ab0a4b06a96bbb 100644 --- a/src/libraries/System.Reflection.Context/src/System.Reflection.Context.csproj +++ b/src/libraries/System.Reflection.Context/src/System.Reflection.Context.csproj @@ -2,7 +2,6 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.1;netstandard2.0 - false false true true diff --git a/src/libraries/System.Reflection.MetadataLoadContext/Directory.Build.props b/src/libraries/System.Reflection.MetadataLoadContext/Directory.Build.props new file mode 100644 index 00000000000000..760f934398477e --- /dev/null +++ b/src/libraries/System.Reflection.MetadataLoadContext/Directory.Build.props @@ -0,0 +1,6 @@ + + + + false + + diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj index 461be58422d22d..c155c10874a6f2 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj @@ -4,7 +4,6 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) System.Reflection true - false false true $(NoWarn);CA1865 diff --git a/src/libraries/System.Resources.Extensions/Directory.Build.props b/src/libraries/System.Resources.Extensions/Directory.Build.props new file mode 100644 index 00000000000000..760f934398477e --- /dev/null +++ b/src/libraries/System.Resources.Extensions/Directory.Build.props @@ -0,0 +1,6 @@ + + + + false + + diff --git a/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj b/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj index 947932941ffc44..4dbcfda830cfab 100644 --- a/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj +++ b/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj @@ -4,7 +4,6 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) true $(DefineConstants);RESOURCES_EXTENSIONS - false true false true diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/Directory.Build.props b/src/libraries/System.Runtime.InteropServices.JavaScript/Directory.Build.props index d68d22c1b917f8..4733ac5e517b31 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/Directory.Build.props +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/Directory.Build.props @@ -3,5 +3,6 @@ Microsoft true + false \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj index 551cf32384d450..9643ac9aed0f7f 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj @@ -3,7 +3,6 @@ $(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent) true - false false diff --git a/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props b/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props index 7d407028f6632b..6fa3721eb042af 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props +++ b/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props @@ -5,5 +5,6 @@ true browser;wasi;ios;tvos;maccatalyst + false diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj index 1f50e28449bf3e..86bf7835337ec8 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj @@ -2,7 +2,6 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum) - false true Provides support for importing and exporting xsd schemas for DataContractSerializer. diff --git a/src/libraries/System.ServiceModel.Syndication/Directory.Build.props b/src/libraries/System.ServiceModel.Syndication/Directory.Build.props new file mode 100644 index 00000000000000..760f934398477e --- /dev/null +++ b/src/libraries/System.ServiceModel.Syndication/Directory.Build.props @@ -0,0 +1,6 @@ + + + + false + + diff --git a/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj b/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj index c01a599cc31f2d..c5f32e4efda4cb 100644 --- a/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj +++ b/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj @@ -2,7 +2,6 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) - false true false true diff --git a/src/libraries/System.Windows.Extensions/Directory.Build.props b/src/libraries/System.Windows.Extensions/Directory.Build.props index e7e8cb9ac081be..1de3e8042fb855 100644 --- a/src/libraries/System.Windows.Extensions/Directory.Build.props +++ b/src/libraries/System.Windows.Extensions/Directory.Build.props @@ -3,5 +3,6 @@ Open windows + false \ No newline at end of file diff --git a/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj b/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj index 2925f54d005adb..d55312a08d6c53 100644 --- a/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj +++ b/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj @@ -4,7 +4,6 @@ $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent);$(NetCoreAppMinimum)-windows;$(NetCoreAppMinimum) $(TargetFrameworks);$(NetCoreAppPrevious)-windows;$(NetCoreAppPrevious) true - false false true Provides miscellaneous Windows-specific types From d608d1e48b2e655e3db3adcabef64b503ae2c604 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 29 Jul 2025 10:25:37 -0700 Subject: [PATCH 07/15] Set IsAotCompatible for ref projects --- src/libraries/Directory.Build.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Directory.Build.props b/src/libraries/Directory.Build.props index 46bb87f01531d2..33938989e386de 100644 --- a/src/libraries/Directory.Build.props +++ b/src/libraries/Directory.Build.props @@ -48,8 +48,8 @@ enable annotations - - true + + true From b3a78da0d24cc64452ff3f28ca5564d946d05d1d Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 29 Jul 2025 10:29:12 -0700 Subject: [PATCH 08/15] Set IsAotCompatible for System.Runtime.InteropServices.JavaScript --- .../Directory.Build.props | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/Directory.Build.props b/src/libraries/System.Runtime.InteropServices.JavaScript/Directory.Build.props index 4733ac5e517b31..d68d22c1b917f8 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/Directory.Build.props +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/Directory.Build.props @@ -3,6 +3,5 @@ Microsoft true - false \ No newline at end of file From e865a29005e5efb234b4c1f8825a723770dd3f82 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 29 Jul 2025 10:39:17 -0700 Subject: [PATCH 09/15] Add CompilerVisibleProperty --- .../build/Microsoft.NET.ILLink.Analyzers.props | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/build/Microsoft.NET.ILLink.Analyzers.props b/src/tools/illink/src/ILLink.RoslynAnalyzer/build/Microsoft.NET.ILLink.Analyzers.props index 3284f19567179d..18ae6cb8fd5e8b 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/build/Microsoft.NET.ILLink.Analyzers.props +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/build/Microsoft.NET.ILLink.Analyzers.props @@ -1,8 +1,10 @@ - - - - + + + + + + From be200615161b670d6c6b0865944480ff9ef6fa99 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 31 Jul 2025 09:38:33 -0700 Subject: [PATCH 10/15] Fix InteropServices.JavaScript The IsAotCompatible opt-out was accidentally added back after being intentionally removed due to a bad merge. --- .../Directory.Build.props | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/Directory.Build.props b/src/libraries/System.Runtime.InteropServices.JavaScript/Directory.Build.props index 4733ac5e517b31..d68d22c1b917f8 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/Directory.Build.props +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/Directory.Build.props @@ -3,6 +3,5 @@ Microsoft true - false \ No newline at end of file From 06bd7ef87f31b596d0a7046d739a163fcc6dadb2 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 31 Jul 2025 09:40:34 -0700 Subject: [PATCH 11/15] Build libs --- eng/pipelines/runtime-linker-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/runtime-linker-tests.yml b/eng/pipelines/runtime-linker-tests.yml index 9df8042e7af0af..5649a0d782d468 100644 --- a/eng/pipelines/runtime-linker-tests.yml +++ b/eng/pipelines/runtime-linker-tests.yml @@ -82,7 +82,7 @@ extends: or( eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_illink.containsChange'], true), eq(variables['isRollingBuild'], true)) - buildArgs: -s tools.illinktests -test -c $(_BuildConfig) + buildArgs: -s libs+tools.illinktests -test -c $(_BuildConfig) # # Build Release config vertical for Windows, Linux, and OSX From 7def218461893022ed8c5753513dbc370b2441e9 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 31 Jul 2025 10:23:08 -0700 Subject: [PATCH 12/15] Share assembly check logic --- .../RequiresAnalyzerBase.cs | 33 +++++++++++++++ .../RequiresDynamicCodeAnalyzer.cs | 40 ++++--------------- .../RequiresUnreferencedCodeAnalyzer.cs | 40 ++++--------------- 3 files changed, 49 insertions(+), 64 deletions(-) diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs index 284e403f158e9c..a8b010bdc292d7 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs @@ -390,5 +390,38 @@ ImmutableArray arguments { return false; } + + protected void CheckReferencedAssemblies( + CompilationAnalysisContext context, + string msbuildPropertyName, + string assemblyMetadataName, + DiagnosticDescriptor diagnosticDescriptor) + { + var options = context.Options; + if (!IsAnalyzerEnabled(options)) + return; + + if (!options.IsMSBuildPropertyValueTrue(msbuildPropertyName)) + return; + + foreach (var reference in context.Compilation.References) + { + var refAssembly = context.Compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol; + if (refAssembly is null) + continue; + + var assemblyMetadata = refAssembly.GetAttributes().FirstOrDefault(attr => + attr.AttributeClass?.Name == "AssemblyMetadataAttribute" && + attr.ConstructorArguments.Length == 2 && + attr.ConstructorArguments[0].Value?.ToString() == assemblyMetadataName && + string.Equals(attr.ConstructorArguments[1].Value?.ToString(), "True", StringComparison.OrdinalIgnoreCase)); + + if (assemblyMetadata is null) + { + var diag = Diagnostic.Create(diagnosticDescriptor, Location.None, refAssembly.Name); + context.ReportDiagnostic(diag); + } + } + } } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs index 9593a47a0ac6c8..a8b6714fb8a282 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs @@ -28,37 +28,6 @@ public sealed class RequiresDynamicCodeAnalyzer : RequiresAnalyzerBase public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(s_requiresDynamicCodeRule, s_requiresDynamicCodeAttributeMismatch, s_requiresDynamicCodeOnStaticCtor, s_requiresDynamicCodeOnEntryPoint, s_referenceNotMarkedIsAotCompatibleRule); - private void CheckReferencedAssembliesForAotCompatible(CompilationAnalysisContext context) - { - var options = context.Options; - if (!IsAnalyzerEnabled(options)) - return; - - if (!options.IsMSBuildPropertyValueTrue(MSBuildPropertyOptionNames.VerifyReferenceAotCompatibility)) - return; - - foreach (var reference in context.Compilation.References) - { - var refAssembly = context.Compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol; - if (refAssembly is null) - continue; - - var isAotCompatible = refAssembly.GetAttributes().FirstOrDefault(attr => - attr.AttributeClass?.Name == "AssemblyMetadataAttribute" && - attr.ConstructorArguments.Length == 2 && - attr.ConstructorArguments[0].Value?.ToString() == "IsAotCompatible" && - string.Equals(attr.ConstructorArguments[1].Value?.ToString(), "True", StringComparison.OrdinalIgnoreCase)); - - if (isAotCompatible is null) - { - var diag = Diagnostic.Create(s_referenceNotMarkedIsAotCompatibleRule, - Location.None, - refAssembly.Name); - context.ReportDiagnostic(diag); - } - } - } - private protected override string RequiresAttributeName => RequiresDynamicCodeAttribute; internal override string RequiresAttributeFullyQualifiedName => FullyQualifiedRequiresDynamicCodeAttribute; @@ -196,7 +165,14 @@ private protected override bool IsRequiresCheck(IPropertySymbol propertySymbol, } private protected override ImmutableArray> ExtraCompilationActions => - ImmutableArray.Create>(CheckReferencedAssembliesForAotCompatible); + ImmutableArray.Create>((context) => + { + CheckReferencedAssemblies( + context, + MSBuildPropertyOptionNames.VerifyReferenceAotCompatibility, + "IsAotCompatible", + s_referenceNotMarkedIsAotCompatibleRule); + }); protected override bool VerifyAttributeArguments(AttributeData attribute) => attribute.ConstructorArguments.Length >= 1 && attribute.ConstructorArguments is [{ Type.SpecialType: SpecialType.System_String }, ..]; diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs index 1e4ff65dda4e51..09d2625d56b0aa 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs @@ -49,37 +49,6 @@ public sealed class RequiresUnreferencedCodeAnalyzer : RequiresAnalyzerBase internal override bool IsAnalyzerEnabled(AnalyzerOptions options) => options.IsMSBuildPropertyValueTrue(MSBuildPropertyOptionNames.EnableTrimAnalyzer); - private void CheckReferencedAssembliesForTrimmable(CompilationAnalysisContext context) - { - var options = context.Options; - if (!IsAnalyzerEnabled(options)) - return; - - if (!options.IsMSBuildPropertyValueTrue(MSBuildPropertyOptionNames.VerifyReferenceTrimCompatibility)) - return; - - foreach (var reference in context.Compilation.References) - { - var refAssembly = context.Compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol; - if (refAssembly is null) - continue; - - var isTrimmable = refAssembly.GetAttributes().FirstOrDefault(attr => - attr.AttributeClass?.Name == "AssemblyMetadataAttribute" && - attr.ConstructorArguments.Length == 2 && - attr.ConstructorArguments[0].Value?.ToString() == "IsTrimmable" && - string.Equals(attr.ConstructorArguments[1].Value?.ToString(), "True", StringComparison.OrdinalIgnoreCase)); - - if (isTrimmable is null) - { - var diag = Diagnostic.Create(s_referenceNotMarkedIsTrimmableRule, - Location.None, - refAssembly.Name); - context.ReportDiagnostic(diag); - } - } - } - private protected override bool IsRequiresCheck(IPropertySymbol propertySymbol, Compilation compilation) { // "IsUnreferencedCodeSupported" is treated as a requires check for testing purposes only, and @@ -110,7 +79,14 @@ protected override bool CreateSpecialIncompatibleMembersDiagnostic( } private protected override ImmutableArray> ExtraCompilationActions => - ImmutableArray.Create>(CheckReferencedAssembliesForTrimmable); + ImmutableArray.Create>((context) => + { + CheckReferencedAssemblies( + context, + MSBuildPropertyOptionNames.VerifyReferenceTrimCompatibility, + "IsTrimmable", + s_referenceNotMarkedIsTrimmableRule); + }); protected override bool VerifyAttributeArguments(AttributeData attribute) => RequiresUnreferencedCodeUtils.VerifyRequiresUnreferencedCodeAttributeArguments(attribute); From 0a9aa8bfe1fe1d538cb46c1001712be6869dd82a Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 31 Jul 2025 11:02:12 -0700 Subject: [PATCH 13/15] Build libs first --- eng/pipelines/runtime-linker-tests.yml | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/eng/pipelines/runtime-linker-tests.yml b/eng/pipelines/runtime-linker-tests.yml index 5649a0d782d468..6cd3f6fa8ee148 100644 --- a/eng/pipelines/runtime-linker-tests.yml +++ b/eng/pipelines/runtime-linker-tests.yml @@ -62,6 +62,27 @@ extends: - stage: Build jobs: + + # + # Build Release libs subset so that Roslyn analyzer tests can use live ref pack + # + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + buildConfig: release + platforms: + - windows_x64 + - osx_x64 + - linux_x64 + jobParameters: + nameSuffix: Libraries_Release + condition: + or( + eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_illink.containsChange'], true), + eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true), + eq(variables['isRollingBuild'], true)) + buildArgs: -s libs -c $(_BuildConfig) + # # Build and Test ILLink in Release config vertical for Windows, Linux and OSX # @@ -82,7 +103,7 @@ extends: or( eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_illink.containsChange'], true), eq(variables['isRollingBuild'], true)) - buildArgs: -s libs+tools.illinktests -test -c $(_BuildConfig) + buildArgs: -s tools.illinktests -test -c $(_BuildConfig) # # Build Release config vertical for Windows, Linux, and OSX @@ -103,7 +124,7 @@ extends: or( eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true), eq(variables['isRollingBuild'], true)) - buildArgs: -s clr+libs+tools.illink+host.native -c $(_BuildConfig) + buildArgs: -s clr+tools.illink+host.native -c $(_BuildConfig) postBuildSteps: - template: /eng/pipelines/libraries/execute-trimming-tests-steps.yml From 0a2673c342ee4690554a9370808acd3e513e8ebe Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 31 Jul 2025 12:51:15 -0700 Subject: [PATCH 14/15] Use postBuildSteps --- eng/pipelines/runtime-linker-tests.yml | 29 ++++++-------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/eng/pipelines/runtime-linker-tests.yml b/eng/pipelines/runtime-linker-tests.yml index 6cd3f6fa8ee148..6d0fff6ee5d39e 100644 --- a/eng/pipelines/runtime-linker-tests.yml +++ b/eng/pipelines/runtime-linker-tests.yml @@ -62,27 +62,6 @@ extends: - stage: Build jobs: - - # - # Build Release libs subset so that Roslyn analyzer tests can use live ref pack - # - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - buildConfig: release - platforms: - - windows_x64 - - osx_x64 - - linux_x64 - jobParameters: - nameSuffix: Libraries_Release - condition: - or( - eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_illink.containsChange'], true), - eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true), - eq(variables['isRollingBuild'], true)) - buildArgs: -s libs -c $(_BuildConfig) - # # Build and Test ILLink in Release config vertical for Windows, Linux and OSX # @@ -103,7 +82,11 @@ extends: or( eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_illink.containsChange'], true), eq(variables['isRollingBuild'], true)) - buildArgs: -s tools.illinktests -test -c $(_BuildConfig) + # Build libs subset first so that Roslyn analyzer tests can use live ref pack + buildArgs: -s libs -c $(_BuildConfig) + postBuildSteps: + - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -ci -arch ${{ parameters.archType }} $(_osParameter) -s tools.illinktests -test -c $(_BuildConfig) $(crossArg) $(_officialBuildParameter) + displayName: Run ILLink Tests # # Build Release config vertical for Windows, Linux, and OSX @@ -124,7 +107,7 @@ extends: or( eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true), eq(variables['isRollingBuild'], true)) - buildArgs: -s clr+tools.illink+host.native -c $(_BuildConfig) + buildArgs: -s clr+libs+tools.illink+host.native -c $(_BuildConfig) postBuildSteps: - template: /eng/pipelines/libraries/execute-trimming-tests-steps.yml From cf86341960584a7b662e74ca249e0ac799c1348c Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 1 Aug 2025 10:40:31 -0700 Subject: [PATCH 15/15] PR feedback - Don't mention attribute in messages - Build libs.sfx instead of libs --- eng/pipelines/runtime-linker-tests.yml | 4 ++-- src/tools/illink/src/ILLink.Shared/SharedStrings.resx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/pipelines/runtime-linker-tests.yml b/eng/pipelines/runtime-linker-tests.yml index 6d0fff6ee5d39e..eaf4c68ec9799c 100644 --- a/eng/pipelines/runtime-linker-tests.yml +++ b/eng/pipelines/runtime-linker-tests.yml @@ -82,8 +82,8 @@ extends: or( eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_illink.containsChange'], true), eq(variables['isRollingBuild'], true)) - # Build libs subset first so that Roslyn analyzer tests can use live ref pack - buildArgs: -s libs -c $(_BuildConfig) + # Build libs.sfx subset first so that Roslyn analyzer tests can use live ref pack + buildArgs: -s libs.sfx -c $(_BuildConfig) postBuildSteps: - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -ci -arch ${{ parameters.archType }} $(_osParameter) -s tools.illinktests -test -c $(_BuildConfig) $(crossArg) $(_officialBuildParameter) displayName: Run ILLink Tests diff --git a/src/tools/illink/src/ILLink.Shared/SharedStrings.resx b/src/tools/illink/src/ILLink.Shared/SharedStrings.resx index f9832c591d102a..aaa57abe34b60b 100644 --- a/src/tools/illink/src/ILLink.Shared/SharedStrings.resx +++ b/src/tools/illink/src/ILLink.Shared/SharedStrings.resx @@ -1243,12 +1243,12 @@ Referenced assembly is not marked as trimmable. - Referenced assembly '{0}' is not marked with AssemblyMetadataAttribute IsTrimmable=True and may not be compatible with trimming. + Referenced assembly '{0}' is not built with `true` and may not be compatible with trimming. Referenced assembly is not marked as AOT-compatible. - Referenced assembly '{0}' is not marked with AssemblyMetadataAttribute IsAotCompatible=True and may not be compatible with AOT. + Referenced assembly '{0}' is not built with `true` and may not be compatible with AOT.