From ca3a36b6c40eec68bc89ba35137fcf08d1bb5035 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 12 Apr 2021 17:20:55 -0700 Subject: [PATCH 01/41] Document new linker options and trimming libraries --- docs/core/deploying/trimming-libraries.md | 161 ++++++++++++++++++++++ docs/core/deploying/trimming-options.md | 46 ++++++- docs/fundamentals/toc.yml | 2 + 3 files changed, 205 insertions(+), 4 deletions(-) create mode 100644 docs/core/deploying/trimming-libraries.md diff --git a/docs/core/deploying/trimming-libraries.md b/docs/core/deploying/trimming-libraries.md new file mode 100644 index 0000000000000..e3b8876f33474 --- /dev/null +++ b/docs/core/deploying/trimming-libraries.md @@ -0,0 +1,161 @@ +--- +title: Trimming libraries +description: Learn how to prepare libraries for trimming. +author: sbomer +ms.author: svbomer +ms.date: 08/25/2020 +--- + +# Trimming libraries + +## Trim warnings for libraries + +`PublishTrimmed` will produce trim analysis [warnings](trimming-options.md#analysis-warnings) for patterns that are not statically understood to be compatible with trimming, including patterns in your code and in dependencies. You may see warnings like `warning IL2104: Assembly 'SomeAssembly' produced trim warnings`. + +This means that the library contained patterns which are not guaranteed to work in the context of the trimmed app, and may result in a broken app. Consider contacting the author to see if the library can be annotated for trimming. + +If your app only uses parts of the library that are compatible with trimming, consider [enabling trimming](trimming-options.md#trim-additional-assemblies) of this library if it is not already being trimmed. This will only produce warnings if your app uses problematic parts of the library. (You can also [show detailed warnings](trimming-options.md#showing-detailed-warnings) for the library to see which parts of it are problematic.) + +You may also encounter more detailed warnings originating from your own `ProjectReference` dependencies. In either case, to make your library work in trimmed apps, you need to ensure that it doesn't use patterns which are incompatible with trimming. Follow these instructions to show and resolve static analysis warnings to prepare a library for trimming. + +Use the .NET 6 SDK for the best experience. It is possible to [show analysis warnings](trimming-options.md#analysis-warnings) in .NET 5, but this will show detailed warnings for every library, including framework libraries. These instructions assume you are using the .NET 6 SDK. + +## Enabling library trim warnings + +### Incomplete Roslyn analyzer + +During development, you may set `true` (in .NET 6+) in your library project to get a _limited_ set of warnings from the Roslyn analyzer. This analyzer is incomplete and should only be used as a convenience. It is important to follow the next steps to ensure that your library is compatible with trimming. + +### Showing all warnings + +To show all analysis warnings for your library, including warnings about dependencies, create a project like the following that references your library, and publish it with `PublishTrimmed`. + +- Publishing a self-contained app ensures that the library is analyzed in a context where its dependencies are available, so that you are alerted if your library uses any code from dependencies that is incompatible with trimming. + +- `TrimmerRootAssembly` ensures that every part of the library is analyzed. This is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`, which would otherwise let trimming remove the unused library without analyzing it. + +- `link` ensures that only used parts of dependencies are analyzed. Without this option, you would see warnings originating from _any_ part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "True")]`, including parts that are unused by your library. + +- `link` is implied by `PublishTrimmed` in the .NET SDK. It is only needed if the app targets form factors like Android where the trim analysis warnings are disabled by default. Consult the documentation for your SDK. + +```xml + + + + Exe + net6.0 + + linux-x64 + true + link + + false + + + + + + + + +``` + +```dotnetcli +dotnet publish +``` + +You can also follow the same pattern for multiple libraries, adding them all to the same project as `ProjectReference` and `TrimmerRootAssembly` item to see trim analysis warnings for more than one library at a time, but note that this will warn about dependencies if _any_ of the root libraries use a trim-unfriendly API in a dependency. To see warnings that have to do with only a particular library, reference that library only. + +Note that the analysis results depend on the implementation details of your dependencies. If you update to a new version of a dependency, this may introduce analysis warnings if the new version added non-understood reflection patterns, even if there were no API changes. In other words, introducing trim analysis warnings to a library is a breaking change when the library is used with `PublishTrimmed`. + +## Resolving trim warnings + +The above steps will produce warnings about code that may cause problems when used in a trimmed app. Here are a few examples of the most common kinds of warnings you may encounter, with recommendations for fixing them. + +### RequiresUnreferencedCode + +```csharp +using System.Diagnostics.CodeAnalysis; + +public class MyLibrary +{ + public static void Foo() + { + // warning IL2026 : MyLibrary.Foo: Using method 'MyLibrary.Bar' which has + // 'RequiresUnreferencedCodeAttribute' can break functionality + // when trimming application code. + Bar(); + } + + [RequiresUnreferencedCode("Bar does something incompatible with trimming.")] + static void Bar() + { + } +} +``` + +This means the library calls a method which has explicitly been annotated as incompatible with trimming, using [`RequiresUnreferencedCodeAttribute`]( +https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.requiresunreferencedcodeattribute?view=net-5.0). To get rid of the warning, consider whether `Foo` needs to call `Bar` to do its job. If so, annotate the caller `Foo` with `RequiresUnreferencedCode` as well; this will "bubble up" the warning so that callers of `Foo` get a warning instead. Once you have "bubbled up" the attribute all the way to public APIs (so that these warnings are produced only for public methods, if at all), you are done. Apps which call your library will now get warnings if they call those public APIs, but these will no longer produce warnings like `IL2104: Assembly 'MyLibrary` produced trim warnings`. + +### DynamicallyAccessedMembers + +```csharp +using System.Diagnostics.CodeAnalysis; + +public class MyLibrary +{ + public static void Foo(Type type) + { + // warning IL2067: MyLibrary.Foo(Type): 'type' argument does not satisfy + // 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'MyLibrary.UseMethods(Type)'. + // The parameter 't' of method 'MyLibrary.Foo(Type)' does not have matching annotations. + UseMethods(type); + } + + static void UseMethods( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] + Type type) + { + foreach (var method in type.GetMethods()) + { + // ... + } + } +} +``` + +Here, `Foo` is calling a method which takes a `Type` argument that is annotated with a `DynamicallyAccessedMembers` requirement. The requirement states that the value passed in as this argument must represent a type whose public methods are available. In this case, you can fix this by adding the same requirement to the parameter of `Foo`. Like above, once you have bubbled up such warnings to public APIs, you are done. + +```csharp + static Type type; + + static void Bar() + { + // warning IL2077: MyLibrary.Bar(Type): 'type' argument does not satisfy + // 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'MyLibrary.UseMethods(Type)'. + // The field 'System.Type MyLibrary::type' does not have matching annotations. + UseMethods(type); + } +``` + +Similarly, here the problem is that the field `type` is passed into a parameter with these requinements. You can fix it by adding `DynamicallyAccessedMembers` to the field. This will warn about code that assigns incompatible values to the field instead. Sometimes this process will continue until a public API is annotated, and other times it will end when a concrete type flows into a location with these requirements. For example: + +```csharp + [DynamicallyAccessedMembers(DynamicallyAccessedMembers.PublicMethods)] + static Type type; + + static void Baz() + { + MyLibrary.type = typeof(System.Tuple); + } +``` + +In this case the trim analysis will simply keep public methods of `System.Tuple`, and will not produce further warnings. + +### Recommendations + +In general, try to avoid reflection if possible, and when using reflection limit it in scope so that it is reachable only from a small part of the library. For example, avoid using non-understood patterns in places like static constructors that will result in the warning propagating to all members of the class. + +- In some cases, you will be able to mechanically propagate warnings through your code without issues. Sometimes this will result in much of your public API being annotated with `RequiresUnreferencedCode`, which is the right thing to do if the library indeed behaves in ways that can't be understood statically by the trim analysis. +- In other cases, you might discover that your code uses patterns which can't be expressed in terms of the `DynamicallyAccessedMembers` attributes, even if it only uses reflection to operate on statically-known types. In these cases, you may need to reorganize some of your code to make it follow an analyzable pattern. +- Sometimes the existing design of an API will render it mostly trim-incompatible, and you may need to find other ways to accomplish what it is doing. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed. diff --git a/docs/core/deploying/trimming-options.md b/docs/core/deploying/trimming-options.md index 53f453e7238b4..67f2a9f867624 100644 --- a/docs/core/deploying/trimming-options.md +++ b/docs/core/deploying/trimming-options.md @@ -9,27 +9,47 @@ ms.date: 08/25/2020 The following MSBuild properties and items influence the behavior of [trimmed self-contained deployments](trim-self-contained.md). Some of the options mention `ILLink`, which is the name of the underlying tool that implements trimming. More information about the underlying tool can be found at the [Linker documentation](https://github.com/mono/linker/tree/master/docs). +Trimming with `PublishTrimmed` was introduced in .NET Core 3.0. The other options are available only in .NET 5 and above. + ## Enable trimming - `true` Enable trimming during publish, with the default settings defined by the SDK. -When using `Microsoft.NET.Sdk`, this will perform assembly-level trimming of the framework assemblies from the netcoreapp runtime pack. Application code and non-framework libraries are not trimmed. Other SDKs may define different defaults. +When using `Microsoft.NET.Sdk`, this will trim the framework assemblies from the netcoreapp runtime pack. Application code and non-framework libraries are not trimmed. Other SDKs may define different defaults. ## Trimming granularity The following granularity settings control how aggressively unused IL is discarded. This can be set as a property, or as metadata on an [individual assembly](#trimmed-assemblies). +- `link` + + Enable member-level trimming, which removes unused members from types. + - `copyused` Enable assembly-level trimming, which will keep an entire assembly if any part of it is used (in a statically understood way). -- `link` +Assemblies with `true` metadata but no explicit `TrimMode` will use the global `TrimMode`. The default `TrimMode` for `Microsoft.NET.Sdk` is `link` in .NET 6+, and `copyused` in previous versions. - Enable member-level trimming, which removes unused members from types. +## Trim additional assemblies -Assemblies with `true` metadata but no explicit `TrimMode` will use the global `TrimMode`. The default `TrimMode` for `Microsoft.NET.Sdk` is `copyused`. +In .NET 6+, `PublishTrimmed` trims assemblies with the assembly-level attribute + +```csharp +[AssemblyMetadata("IsTrimmable", "True")] +``` + +which includes the framework libraries. In .NET 6+, you can also opt in to trimming for a library without this attribute, specifying the assembly by name (without the `.dll` extension). + +```xml + + + +``` + +This is equivalent to setting MSBuild metadata `true` for the assembly in `ManagedAssemblyToLink` (see below). ## Trimmed assemblies @@ -46,6 +66,8 @@ When publishing a trimmed app, the SDK computes an `ItemGroup` called `ManagedAs ``` +You can also use this to override the trimming behavior specified by the library author, by setting `false` for an assembly with `[AssemblyMetadata("IsTrimmable", "True"])`. + Do not add or remove items to/from `ManagedAssemblyToLink`, because the SDK computes this set during publish and expects it not to change. The supported metadata is: - `true` @@ -56,6 +78,10 @@ Do not add or remove items to/from `ManagedAssemblyToLink`, because the SDK comp Control the [trimming granularity](#trimming-granularity) of this assembly. This takes precedence over the global `TrimMode`. Setting `TrimMode` on an assembly implies `true`. +- `True` or `False` + + Control whether to show [single warnings](#showing-detailed-warnings) for this assembly. + ## Root assemblies All assemblies that do not have `true` are considered roots for the analysis, which means that they and all of their statically understood dependencies will be kept. Additional assemblies may be "rooted" by name (without the `.dll` extension): @@ -98,6 +124,8 @@ Trimming will remove IL that is not statically reachable. Apps that use reflecti This will include warnings about the entire app, including your own code, library code, and framework code. +## + ## Warning versions Trim analysis respects the [`AnalysisLevel`](../project-sdk/msbuild-props.md#analysislevel) property that controls the version of analysis warnings across the SDK. There is another property that controls the version of trim analysis warnings independently (similar to `WarningLevel` for the compiler): @@ -114,6 +142,16 @@ Individual [warning codes](https://github.com/mono/linker/blob/master/docs/error Don't treat ILLink warnings as errors. This may be useful to avoid turning trim analysis warnings into errors when treating compiler warnings as errors globally. +## Showing detailed warnings + +In .NET 6+, trim analysis will produce at most one warning for each assembly that comes from a `PackageReference`, indicating that the assembly's internals are not compatible with trimming. You can also show individual warnings for all assemblies: + +- `false` + + Show detailed warnings for all assemblies, instead of collapsing them to a single warning per assembly. + +The defaults show detailed warnings for the project assembly and `ProjectReference`s. `` can also be set as metadata on an [individual assembly](#trimmed-assemblies) to control the warning behavior for that assembly only. + ## Removing symbols Symbols will normally be trimmed to match the trimmed assemblies. You can also remove all symbols: diff --git a/docs/fundamentals/toc.yml b/docs/fundamentals/toc.yml index de70ce684eac0..5d0c026049bc9 100644 --- a/docs/fundamentals/toc.yml +++ b/docs/fundamentals/toc.yml @@ -1367,6 +1367,8 @@ items: href: ../core/deploying/trim-self-contained.md - name: Options href: ../core/deploying/trimming-options.md + - name: Preparing libraries for trimming + href: ../core/deploying/trimming-libraries.md - name: Runtime package store href: ../core/deploying/runtime-store.md - name: Runtime Identifier (RID) catalog From 829d6f2906125384d15997a2795a79abfa210689 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 12 Apr 2021 17:23:19 -0700 Subject: [PATCH 02/41] Fix TOC --- docs/fundamentals/toc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fundamentals/toc.yml b/docs/fundamentals/toc.yml index 5d0c026049bc9..3afcf756970c5 100644 --- a/docs/fundamentals/toc.yml +++ b/docs/fundamentals/toc.yml @@ -1367,7 +1367,7 @@ items: href: ../core/deploying/trim-self-contained.md - name: Options href: ../core/deploying/trimming-options.md - - name: Preparing libraries for trimming + - name: Trimming libraries href: ../core/deploying/trimming-libraries.md - name: Runtime package store href: ../core/deploying/runtime-store.md From 02d9251dfb5fa78fdce658d2538ea9dfbd2bcbb4 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 12 Apr 2021 17:43:26 -0700 Subject: [PATCH 03/41] Document EnableTrimAnalyzer And fix typos, links --- docs/core/deploying/trimming-libraries.md | 6 +++--- docs/core/deploying/trimming-options.md | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/core/deploying/trimming-libraries.md b/docs/core/deploying/trimming-libraries.md index e3b8876f33474..a47c13ebc7b6d 100644 --- a/docs/core/deploying/trimming-libraries.md +++ b/docs/core/deploying/trimming-libraries.md @@ -24,7 +24,7 @@ Use the .NET 6 SDK for the best experience. It is possible to [show analysis war ### Incomplete Roslyn analyzer -During development, you may set `true` (in .NET 6+) in your library project to get a _limited_ set of warnings from the Roslyn analyzer. This analyzer is incomplete and should only be used as a convenience. It is important to follow the next steps to ensure that your library is compatible with trimming. +During development, you may set `true` (in .NET 6+) in your library project to get a _limited_ set of warnings from the Roslyn analyzer. This analyzer is incomplete and should only be used as a convenience. It is important to follow the next steps to ensure that your library is compatible with trimming. ### Showing all warnings @@ -95,7 +95,7 @@ public class MyLibrary ``` This means the library calls a method which has explicitly been annotated as incompatible with trimming, using [`RequiresUnreferencedCodeAttribute`]( -https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.requiresunreferencedcodeattribute?view=net-5.0). To get rid of the warning, consider whether `Foo` needs to call `Bar` to do its job. If so, annotate the caller `Foo` with `RequiresUnreferencedCode` as well; this will "bubble up" the warning so that callers of `Foo` get a warning instead. Once you have "bubbled up" the attribute all the way to public APIs (so that these warnings are produced only for public methods, if at all), you are done. Apps which call your library will now get warnings if they call those public APIs, but these will no longer produce warnings like `IL2104: Assembly 'MyLibrary` produced trim warnings`. +https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.requiresunreferencedcodeattribute?view=net-5.0). To get rid of the warning, consider whether `Foo` needs to call `Bar` to do its job. If so, annotate the caller `Foo` with `RequiresUnreferencedCode` as well; this will "bubble up" the warning so that callers of `Foo` get a warning instead. Once you have "bubbled up" the attribute all the way to public APIs (so that these warnings are produced only for public methods, if at all), you are done. Apps which call your library will now get warnings if they call those public APIs, but these will no longer produce warnings like `IL2104: Assembly 'MyLibrary' produced trim warnings`. ### DynamicallyAccessedMembers @@ -124,7 +124,7 @@ public class MyLibrary } ``` -Here, `Foo` is calling a method which takes a `Type` argument that is annotated with a `DynamicallyAccessedMembers` requirement. The requirement states that the value passed in as this argument must represent a type whose public methods are available. In this case, you can fix this by adding the same requirement to the parameter of `Foo`. Like above, once you have bubbled up such warnings to public APIs, you are done. +Here, `Foo` is calling a method which takes a `Type` argument that is annotated with a [`DynamicallyAccessedMembers`](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.dynamicallyaccessedmembersattribute?view=net-5.0) requirement. The requirement states that the value passed in as this argument must represent a type whose public methods are available. In this case, you can fix this by adding the same requirement to the parameter of `Foo`. Like above, once you have bubbled up such warnings to public APIs, you are done. ```csharp static Type type; diff --git a/docs/core/deploying/trimming-options.md b/docs/core/deploying/trimming-options.md index 67f2a9f867624..92220ffb3e212 100644 --- a/docs/core/deploying/trimming-options.md +++ b/docs/core/deploying/trimming-options.md @@ -124,7 +124,13 @@ Trimming will remove IL that is not statically reachable. Apps that use reflecti This will include warnings about the entire app, including your own code, library code, and framework code. -## +## Roslyn analyzer + +Setting `PublishTrimmed` in .NET 6+ will also enable a Roslyn analyzer that shows a _limited_ set of analysis warnings. The analyzer may also be enabled or disabled independently of `PublishTrimmed`. + +- `true` + + Enable a Roslyn analyzer for a subset of trim analysis warnings. ## Warning versions From d61dd7e44a77846f0de5d9df02fed6c6bc1cd1a8 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 13 Apr 2021 17:03:27 -0700 Subject: [PATCH 04/41] PR feedback - Move sample up - Call out TrimMode link default - Clarify app vs library - Publish Release --- docs/core/deploying/trimming-libraries.md | 34 ++++++++++++----------- docs/core/deploying/trimming-options.md | 2 +- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/docs/core/deploying/trimming-libraries.md b/docs/core/deploying/trimming-libraries.md index a47c13ebc7b6d..76e92c7a3966f 100644 --- a/docs/core/deploying/trimming-libraries.md +++ b/docs/core/deploying/trimming-libraries.md @@ -8,20 +8,22 @@ ms.date: 08/25/2020 # Trimming libraries -## Trim warnings for libraries +## Trim warnings in apps -`PublishTrimmed` will produce trim analysis [warnings](trimming-options.md#analysis-warnings) for patterns that are not statically understood to be compatible with trimming, including patterns in your code and in dependencies. You may see warnings like `warning IL2104: Assembly 'SomeAssembly' produced trim warnings`. +When publishing an app, `PublishTrimmed` will produce trim analysis [warnings](trimming-options.md#analysis-warnings) (in .NET 6+) for patterns that are not statically understood to be compatible with trimming, including patterns in your code and in dependencies. -This means that the library contained patterns which are not guaranteed to work in the context of the trimmed app, and may result in a broken app. Consider contacting the author to see if the library can be annotated for trimming. +You will encounter detailed warnings originating from your own code and `ProjectReference` dependencies. You may also see warnings like `warning IL2104: Assembly 'SomeAssembly' produced trim warnings` for `PackageReference` libraries. This means that the library contained patterns which are not guaranteed to work in the context of the trimmed app, and may result in a broken app. Consider contacting the author to see if the library can be annotated for trimming. -If your app only uses parts of the library that are compatible with trimming, consider [enabling trimming](trimming-options.md#trim-additional-assemblies) of this library if it is not already being trimmed. This will only produce warnings if your app uses problematic parts of the library. (You can also [show detailed warnings](trimming-options.md#showing-detailed-warnings) for the library to see which parts of it are problematic.) +To resolve warnings originating from the app code, jump ahead to the instructions below to [resolve trim warnings](resolving-trim-warnings.md). If you are interested in making your own `ProjectReference` libraries trim friendly, follow the instructions to [enable library trim warnings](enabling-library-trim-warnings). -You may also encounter more detailed warnings originating from your own `ProjectReference` dependencies. In either case, to make your library work in trimmed apps, you need to ensure that it doesn't use patterns which are incompatible with trimming. Follow these instructions to show and resolve static analysis warnings to prepare a library for trimming. +If your app only uses parts of a library that are compatible with trimming, consider [enabling trimming](trimming-options.md#trim-additional-assemblies) of this library if it is not already being trimmed. This will only produce warnings if your app uses problematic parts of the library. (You can also [show detailed warnings](trimming-options.md#showing-detailed-warnings) for the library to see which parts of it are problematic.) + +## Enabling library trim warnings + +These instructions show how to enable and resolve static analysis warnings to prepare a library for trimming. Follow these steps if you are authoring a library and either want to proactively make your library trimmable, or have been contacted by app authors who encountered trim warnings from your library. Use the .NET 6 SDK for the best experience. It is possible to [show analysis warnings](trimming-options.md#analysis-warnings) in .NET 5, but this will show detailed warnings for every library, including framework libraries. These instructions assume you are using the .NET 6 SDK. -## Enabling library trim warnings - ### Incomplete Roslyn analyzer During development, you may set `true` (in .NET 6+) in your library project to get a _limited_ set of warnings from the Roslyn analyzer. This analyzer is incomplete and should only be used as a convenience. It is important to follow the next steps to ensure that your library is compatible with trimming. @@ -30,14 +32,6 @@ During development, you may set `true` To show all analysis warnings for your library, including warnings about dependencies, create a project like the following that references your library, and publish it with `PublishTrimmed`. -- Publishing a self-contained app ensures that the library is analyzed in a context where its dependencies are available, so that you are alerted if your library uses any code from dependencies that is incompatible with trimming. - -- `TrimmerRootAssembly` ensures that every part of the library is analyzed. This is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`, which would otherwise let trimming remove the unused library without analyzing it. - -- `link` ensures that only used parts of dependencies are analyzed. Without this option, you would see warnings originating from _any_ part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "True")]`, including parts that are unused by your library. - -- `link` is implied by `PublishTrimmed` in the .NET SDK. It is only needed if the app targets form factors like Android where the trim analysis warnings are disabled by default. Consult the documentation for your SDK. - ```xml @@ -61,9 +55,17 @@ To show all analysis warnings for your library, including warnings about depende ``` ```dotnetcli -dotnet publish +dotnet publish -c Release ``` +- Publishing a self-contained app ensures that the library is analyzed in a context where its dependencies are available, so that you are alerted if your library uses any code from dependencies that is incompatible with trimming. + +- `TrimmerRootAssembly` ensures that every part of the library is analyzed. This is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`, which would otherwise let trimming remove the unused library without analyzing it. + +- `link` ensures that only used parts of dependencies are analyzed. Without this option, you would see warnings originating from _any_ part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "True")]`, including parts that are unused by your library. + +- `link` is implied by `PublishTrimmed` in the .NET SDK. It is only needed if the app targets form factors like Android where the trim analysis warnings are disabled by default. Consult the documentation for your SDK. + You can also follow the same pattern for multiple libraries, adding them all to the same project as `ProjectReference` and `TrimmerRootAssembly` item to see trim analysis warnings for more than one library at a time, but note that this will warn about dependencies if _any_ of the root libraries use a trim-unfriendly API in a dependency. To see warnings that have to do with only a particular library, reference that library only. Note that the analysis results depend on the implementation details of your dependencies. If you update to a new version of a dependency, this may introduce analysis warnings if the new version added non-understood reflection patterns, even if there were no API changes. In other words, introducing trim analysis warnings to a library is a breaking change when the library is used with `PublishTrimmed`. diff --git a/docs/core/deploying/trimming-options.md b/docs/core/deploying/trimming-options.md index 92220ffb3e212..26d9788ba9914 100644 --- a/docs/core/deploying/trimming-options.md +++ b/docs/core/deploying/trimming-options.md @@ -25,7 +25,7 @@ The following granularity settings control how aggressively unused IL is discard - `link` - Enable member-level trimming, which removes unused members from types. + Enable member-level trimming, which removes unused members from types. This is the default in .NET 6+. - `copyused` From 471ac2ea63a56bbf412d76d92a01eb15ddeb9c9c Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 13 Apr 2021 17:06:40 -0700 Subject: [PATCH 05/41] Change title to "Preparing libraries for trimming" --- ...mming-libraries.md => preparing-libraries-for-trimming.md} | 4 ++-- docs/fundamentals/toc.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename docs/core/deploying/{trimming-libraries.md => preparing-libraries-for-trimming.md} (99%) diff --git a/docs/core/deploying/trimming-libraries.md b/docs/core/deploying/preparing-libraries-for-trimming.md similarity index 99% rename from docs/core/deploying/trimming-libraries.md rename to docs/core/deploying/preparing-libraries-for-trimming.md index 76e92c7a3966f..c3d3be4caa4b2 100644 --- a/docs/core/deploying/trimming-libraries.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -1,12 +1,12 @@ --- -title: Trimming libraries +title: Preparing libraries for trimming description: Learn how to prepare libraries for trimming. author: sbomer ms.author: svbomer ms.date: 08/25/2020 --- -# Trimming libraries +# Preparing libraries for trimming ## Trim warnings in apps diff --git a/docs/fundamentals/toc.yml b/docs/fundamentals/toc.yml index 3afcf756970c5..af8704076c066 100644 --- a/docs/fundamentals/toc.yml +++ b/docs/fundamentals/toc.yml @@ -1368,7 +1368,7 @@ items: - name: Options href: ../core/deploying/trimming-options.md - name: Trimming libraries - href: ../core/deploying/trimming-libraries.md + href: ../core/deploying/preparing-libraries-for-trimming.md - name: Runtime package store href: ../core/deploying/runtime-store.md - name: Runtime Identifier (RID) catalog From 4350de64d8b08d59904703da5ba0a014119144bd Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 14 Apr 2021 08:00:29 -0700 Subject: [PATCH 06/41] PR feedback - Fix typo - Avoid referencing sections with "above/below" --- docs/core/deploying/preparing-libraries-for-trimming.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index c3d3be4caa4b2..388d48a4c8252 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -14,7 +14,7 @@ When publishing an app, `PublishTrimmed` will produce trim analysis [warnings](t You will encounter detailed warnings originating from your own code and `ProjectReference` dependencies. You may also see warnings like `warning IL2104: Assembly 'SomeAssembly' produced trim warnings` for `PackageReference` libraries. This means that the library contained patterns which are not guaranteed to work in the context of the trimmed app, and may result in a broken app. Consider contacting the author to see if the library can be annotated for trimming. -To resolve warnings originating from the app code, jump ahead to the instructions below to [resolve trim warnings](resolving-trim-warnings.md). If you are interested in making your own `ProjectReference` libraries trim friendly, follow the instructions to [enable library trim warnings](enabling-library-trim-warnings). +To resolve warnings originating from the app code, jump ahead to the instructions on [resolving trim warnings](resolving-trim-warnings.md). If you are interested in making your own `ProjectReference` libraries trim friendly, follow the instructions to [enable library trim warnings](enabling-library-trim-warnings). If your app only uses parts of a library that are compatible with trimming, consider [enabling trimming](trimming-options.md#trim-additional-assemblies) of this library if it is not already being trimmed. This will only produce warnings if your app uses problematic parts of the library. (You can also [show detailed warnings](trimming-options.md#showing-detailed-warnings) for the library to see which parts of it are problematic.) @@ -64,7 +64,7 @@ dotnet publish -c Release - `link` ensures that only used parts of dependencies are analyzed. Without this option, you would see warnings originating from _any_ part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "True")]`, including parts that are unused by your library. -- `link` is implied by `PublishTrimmed` in the .NET SDK. It is only needed if the app targets form factors like Android where the trim analysis warnings are disabled by default. Consult the documentation for your SDK. +- `false` is implied by `PublishTrimmed` in the .NET SDK. It is only needed if the app targets form factors like Android where the trim analysis warnings are disabled by default. Consult the documentation for your SDK. You can also follow the same pattern for multiple libraries, adding them all to the same project as `ProjectReference` and `TrimmerRootAssembly` item to see trim analysis warnings for more than one library at a time, but note that this will warn about dependencies if _any_ of the root libraries use a trim-unfriendly API in a dependency. To see warnings that have to do with only a particular library, reference that library only. @@ -126,7 +126,7 @@ public class MyLibrary } ``` -Here, `Foo` is calling a method which takes a `Type` argument that is annotated with a [`DynamicallyAccessedMembers`](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.dynamicallyaccessedmembersattribute?view=net-5.0) requirement. The requirement states that the value passed in as this argument must represent a type whose public methods are available. In this case, you can fix this by adding the same requirement to the parameter of `Foo`. Like above, once you have bubbled up such warnings to public APIs, you are done. +Here, `Foo` is calling a method which takes a `Type` argument that is annotated with a [`DynamicallyAccessedMembers`](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.dynamicallyaccessedmembersattribute?view=net-5.0) requirement. The requirement states that the value passed in as this argument must represent a type whose public methods are available. In this case, you can fix this by adding the same requirement to the parameter of `Foo`. Like with `RequiresUnreferencedCode`, once you have bubbled up such warnings to public APIs, you are done. ```csharp static Type type; From 33efed13b03e5b48eac236c2ea23d01d90d8f118 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 14 Apr 2021 08:11:09 -0700 Subject: [PATCH 07/41] PR feedback Add code snippet for examples after annotation --- .../preparing-libraries-for-trimming.md | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 388d48a4c8252..be509f8840dd2 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -97,7 +97,18 @@ public class MyLibrary ``` This means the library calls a method which has explicitly been annotated as incompatible with trimming, using [`RequiresUnreferencedCodeAttribute`]( -https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.requiresunreferencedcodeattribute?view=net-5.0). To get rid of the warning, consider whether `Foo` needs to call `Bar` to do its job. If so, annotate the caller `Foo` with `RequiresUnreferencedCode` as well; this will "bubble up" the warning so that callers of `Foo` get a warning instead. Once you have "bubbled up" the attribute all the way to public APIs (so that these warnings are produced only for public methods, if at all), you are done. Apps which call your library will now get warnings if they call those public APIs, but these will no longer produce warnings like `IL2104: Assembly 'MyLibrary' produced trim warnings`. +https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.requiresunreferencedcodeattribute?view=net-5.0). To get rid of the warning, consider whether `Foo` needs to call `Bar` to do its job. If so, annotate the caller `Foo` with `RequiresUnreferencedCode` as well; this will "bubble up" the warning so that callers of `Foo` get a warning instead: + +```csharp + // Warn for calls to Foo, but not for Foo's call to Bar. + [RequiresUnreferencedCode("Calls Bar.")] + public static void Foo() + { + // ... + } +``` + +Once you have "bubbled up" the attribute all the way to public APIs (so that these warnings are produced only for public methods, if at all), you are done. Apps which call your library will now get warnings if they call those public APIs, but these will no longer produce warnings like `IL2104: Assembly 'MyLibrary' produced trim warnings`. ### DynamicallyAccessedMembers @@ -126,7 +137,21 @@ public class MyLibrary } ``` -Here, `Foo` is calling a method which takes a `Type` argument that is annotated with a [`DynamicallyAccessedMembers`](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.dynamicallyaccessedmembersattribute?view=net-5.0) requirement. The requirement states that the value passed in as this argument must represent a type whose public methods are available. In this case, you can fix this by adding the same requirement to the parameter of `Foo`. Like with `RequiresUnreferencedCode`, once you have bubbled up such warnings to public APIs, you are done. +Here, `Foo` is calling a method which takes a `Type` argument that is annotated with a [`DynamicallyAccessedMembers`](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.dynamicallyaccessedmembersattribute?view=net-5.0) requirement. The requirement states that the value passed in as this argument must represent a type whose public methods are available. In this case, you can fix this by adding the same requirement to the parameter of `Foo`. + +```csharp + public static void Foo( + // Propagate the requirement to Foo's parameter. + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] + Type type) + { + // ... + } +``` + +Like with `RequiresUnreferencedCode`, once you have bubbled up such warnings to public APIs, you are done. + +Here is another example where an unknown `Type` flows into the annotated method parameter, this time from a field: ```csharp static Type type; From 78b5d5b69ade25c008d6d931811a82f99b6938cc Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 14 Apr 2021 09:03:35 -0700 Subject: [PATCH 08/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: Eric Erhardt --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index be509f8840dd2..48cd56b11efa9 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -22,7 +22,7 @@ If your app only uses parts of a library that are compatible with trimming, cons These instructions show how to enable and resolve static analysis warnings to prepare a library for trimming. Follow these steps if you are authoring a library and either want to proactively make your library trimmable, or have been contacted by app authors who encountered trim warnings from your library. -Use the .NET 6 SDK for the best experience. It is possible to [show analysis warnings](trimming-options.md#analysis-warnings) in .NET 5, but this will show detailed warnings for every library, including framework libraries. These instructions assume you are using the .NET 6 SDK. +Use the .NET 6 SDK for the best experience. It is possible to [show analysis warnings](trimming-options.md#analysis-warnings) in .NET 5, but not all framework assemblies were annotated correctly in .NET 5. Also, this will show detailed warnings for every library, including framework libraries. These instructions assume you are using the .NET 6 SDK. ### Incomplete Roslyn analyzer From e2531fc47949032555a2638011cb4ca9b77c6bbe Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 14 Apr 2021 09:03:57 -0700 Subject: [PATCH 09/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: Eric Erhardt --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 48cd56b11efa9..f8afdbe89c5ed 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -181,7 +181,7 @@ In this case the trim analysis will simply keep public methods of `System.Tuple` ### Recommendations -In general, try to avoid reflection if possible, and when using reflection limit it in scope so that it is reachable only from a small part of the library. For example, avoid using non-understood patterns in places like static constructors that will result in the warning propagating to all members of the class. +In general, try to avoid reflection if possible. When using reflection, limit it in scope so that it is reachable only from a small part of the library. For example, avoid using non-understood patterns in places like static constructors that will result in the warning propagating to all members of the class. - In some cases, you will be able to mechanically propagate warnings through your code without issues. Sometimes this will result in much of your public API being annotated with `RequiresUnreferencedCode`, which is the right thing to do if the library indeed behaves in ways that can't be understood statically by the trim analysis. - In other cases, you might discover that your code uses patterns which can't be expressed in terms of the `DynamicallyAccessedMembers` attributes, even if it only uses reflection to operate on statically-known types. In these cases, you may need to reorganize some of your code to make it follow an analyzable pattern. From 173f8798b9ad03304ad96f7f82b91668ed2307b0 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 14 Apr 2021 09:04:08 -0700 Subject: [PATCH 10/41] Update docs/core/deploying/trimming-options.md Co-authored-by: Eric Erhardt --- docs/core/deploying/trimming-options.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/trimming-options.md b/docs/core/deploying/trimming-options.md index 26d9788ba9914..b80e5fef7be44 100644 --- a/docs/core/deploying/trimming-options.md +++ b/docs/core/deploying/trimming-options.md @@ -154,7 +154,7 @@ In .NET 6+, trim analysis will produce at most one warning for each assembly tha - `false` - Show detailed warnings for all assemblies, instead of collapsing them to a single warning per assembly. + Show all detailed warnings, instead of collapsing them to a single warning per assembly. The defaults show detailed warnings for the project assembly and `ProjectReference`s. `` can also be set as metadata on an [individual assembly](#trimmed-assemblies) to control the warning behavior for that assembly only. From d15cb0d4dfd6b32c32fbdb13a0f1f68a6e4edd35 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 14 Apr 2021 09:35:06 -0700 Subject: [PATCH 11/41] PR feedback - Fix links - Clarify which assemblies are trimmed by default - Clarify which assemblies are affected by per-assembly metadata --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- docs/core/deploying/trimming-options.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index f8afdbe89c5ed..5584d5956f1a1 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -14,7 +14,7 @@ When publishing an app, `PublishTrimmed` will produce trim analysis [warnings](t You will encounter detailed warnings originating from your own code and `ProjectReference` dependencies. You may also see warnings like `warning IL2104: Assembly 'SomeAssembly' produced trim warnings` for `PackageReference` libraries. This means that the library contained patterns which are not guaranteed to work in the context of the trimmed app, and may result in a broken app. Consider contacting the author to see if the library can be annotated for trimming. -To resolve warnings originating from the app code, jump ahead to the instructions on [resolving trim warnings](resolving-trim-warnings.md). If you are interested in making your own `ProjectReference` libraries trim friendly, follow the instructions to [enable library trim warnings](enabling-library-trim-warnings). +To resolve warnings originating from the app code, jump ahead to the instructions on [resolving trim warnings](#resolving-trim-warnings). If you are interested in making your own `ProjectReference` libraries trim friendly, follow the instructions to [enable library trim warnings](#enabling-library-trim-warnings). If your app only uses parts of a library that are compatible with trimming, consider [enabling trimming](trimming-options.md#trim-additional-assemblies) of this library if it is not already being trimmed. This will only produce warnings if your app uses problematic parts of the library. (You can also [show detailed warnings](trimming-options.md#showing-detailed-warnings) for the library to see which parts of it are problematic.) diff --git a/docs/core/deploying/trimming-options.md b/docs/core/deploying/trimming-options.md index b80e5fef7be44..4958ad9ce74d5 100644 --- a/docs/core/deploying/trimming-options.md +++ b/docs/core/deploying/trimming-options.md @@ -17,11 +17,11 @@ Trimming with `PublishTrimmed` was introduced in .NET Core 3.0. The other option Enable trimming during publish, with the default settings defined by the SDK. -When using `Microsoft.NET.Sdk`, this will trim the framework assemblies from the netcoreapp runtime pack. Application code and non-framework libraries are not trimmed. Other SDKs may define different defaults. +This will trim any assemblies which have been configured for trimming. With `Microsoft.NET.Sdk` in .NET 6, this includes the any assemblies with `[AssemblyMetadata("IsTrimmable", "True")]`, which is the case for framework assemblies. In .NET 5, framework assemblies from the netcoreapp runtime pack are configured for trimming via `` MSBuild metadata. Other SDKs may define different defaults. ## Trimming granularity -The following granularity settings control how aggressively unused IL is discarded. This can be set as a property, or as metadata on an [individual assembly](#trimmed-assemblies). +The following granularity settings control how aggressively unused IL is discarded. This can be set as a property affecting all trimmer input assemblies, or as metadata on an [individual assembly](#trimmed-assemblies) which overrides the property setting. - `link` From bbc7a262905d1b9b1660ee3d4a488da62a0cbb04 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 15 Apr 2021 13:32:56 -0700 Subject: [PATCH 12/41] PR feedback - Change example to call reflection directly - Avoid mentioning .NET 5 - Point out benefits of Roslyn analyzer - Avoid Foo/Bar - Recommend not annotating virtuals --- .../preparing-libraries-for-trimming.md | 61 +++++++++---------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 5584d5956f1a1..12be8c705f8d5 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -22,11 +22,13 @@ If your app only uses parts of a library that are compatible with trimming, cons These instructions show how to enable and resolve static analysis warnings to prepare a library for trimming. Follow these steps if you are authoring a library and either want to proactively make your library trimmable, or have been contacted by app authors who encountered trim warnings from your library. -Use the .NET 6 SDK for the best experience. It is possible to [show analysis warnings](trimming-options.md#analysis-warnings) in .NET 5, but not all framework assemblies were annotated correctly in .NET 5. Also, this will show detailed warnings for every library, including framework libraries. These instructions assume you are using the .NET 6 SDK. +Ensure you are using the .NET 6 SDK for these steps. They will not work correctly in previous versions. -### Incomplete Roslyn analyzer +## Enable Roslyn analyzer -During development, you may set `true` (in .NET 6+) in your library project to get a _limited_ set of warnings from the Roslyn analyzer. This analyzer is incomplete and should only be used as a convenience. It is important to follow the next steps to ensure that your library is compatible with trimming. +During development, set `true` (in .NET 6+) in your library project. This will not have any effect on the output, but it will enable trim analysis during build via a Roslyn analyzer. + +The Roslyn analyzer is useful for a fast feedback cycle with IDE integration, but is currently incomplete. It doesn't cover all trim analysis warnings, but the set of patterns it understands will improve over time to give more complete coverage. The Roslyn analyzer also isn't able to analyze the implementations of reference assemblies that you depend on. It is important to follow the next steps to ensure that your library is fully compatible with trimming. ### Showing all warnings @@ -81,30 +83,30 @@ using System.Diagnostics.CodeAnalysis; public class MyLibrary { - public static void Foo() + public static void Method() { - // warning IL2026 : MyLibrary.Foo: Using method 'MyLibrary.Bar' which has + // warning IL2026 : MyLibrary.Method: Using method 'MyLibrary.DynamicBehavior' which has // 'RequiresUnreferencedCodeAttribute' can break functionality // when trimming application code. - Bar(); + DynamicBehavior(); } - [RequiresUnreferencedCode("Bar does something incompatible with trimming.")] - static void Bar() + [RequiresUnreferencedCode("DynamicBehavior is incompatible with trimming.")] + static void DynamicBehavior() { } } ``` This means the library calls a method which has explicitly been annotated as incompatible with trimming, using [`RequiresUnreferencedCodeAttribute`]( -https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.requiresunreferencedcodeattribute?view=net-5.0). To get rid of the warning, consider whether `Foo` needs to call `Bar` to do its job. If so, annotate the caller `Foo` with `RequiresUnreferencedCode` as well; this will "bubble up" the warning so that callers of `Foo` get a warning instead: +https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.requiresunreferencedcodeattribute?view=net-5.0). To get rid of the warning, consider whether `Method` needs to call `DynamicBehavior` to do its job. If so, annotate the caller `Method` with `RequiresUnreferencedCode` as well; this will "bubble up" the warning so that callers of `Method` get a warning instead: ```csharp - // Warn for calls to Foo, but not for Foo's call to Bar. - [RequiresUnreferencedCode("Calls Bar.")] - public static void Foo() + // Warn for calls to Method, but not for Method's call to DynamicBehavior. + [RequiresUnreferencedCode("Calls DynamicBehavior.")] + public static void Method() { - // ... + DynamicBehavior(); // OK. Doesn't warn now. } ``` @@ -117,18 +119,11 @@ using System.Diagnostics.CodeAnalysis; public class MyLibrary { - public static void Foo(Type type) - { - // warning IL2067: MyLibrary.Foo(Type): 'type' argument does not satisfy - // 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'MyLibrary.UseMethods(Type)'. - // The parameter 't' of method 'MyLibrary.Foo(Type)' does not have matching annotations. - UseMethods(type); - } - - static void UseMethods( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] - Type type) + static void UseMethods(Type type) { + // warning IL2070: MyLibrary.UseMethods(Type): 'this' argument does not satisfy + // 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods()'. + // The parameter 't' of method 'MyLibrary.UseMethods(Type)' does not have matching annotations. foreach (var method in type.GetMethods()) { // ... @@ -137,11 +132,11 @@ public class MyLibrary } ``` -Here, `Foo` is calling a method which takes a `Type` argument that is annotated with a [`DynamicallyAccessedMembers`](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.dynamicallyaccessedmembersattribute?view=net-5.0) requirement. The requirement states that the value passed in as this argument must represent a type whose public methods are available. In this case, you can fix this by adding the same requirement to the parameter of `Foo`. +Here, `UseMethods` is calling a reflection method which has a [`DynamicallyAccessedMembers`](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.dynamicallyaccessedmembersattribute?view=net-5.0) requirement. The requirement states that the type's public methods are available. In this case, you can fix this by adding the same requirement to the parameter of `UseMethods`. ```csharp - public static void Foo( - // Propagate the requirement to Foo's parameter. + static void UseMethods( + // State the requirement in the UseMethods parameter. [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) { @@ -149,16 +144,16 @@ Here, `Foo` is calling a method which takes a `Type` argument that is annotated } ``` -Like with `RequiresUnreferencedCode`, once you have bubbled up such warnings to public APIs, you are done. +Now any calls to `UseMethods` will produce warnings if they pass in values which don't satisfy the `PublicMethods` requirement. Like with `RequiresUnreferencedCode`, once you have bubbled up such warnings to public APIs, you are done. Here is another example where an unknown `Type` flows into the annotated method parameter, this time from a field: ```csharp static Type type; - static void Bar() + static void UseMethodsHelper() { - // warning IL2077: MyLibrary.Bar(Type): 'type' argument does not satisfy + // warning IL2077: MyLibrary.UseMethodsHelper(Type): 'type' argument does not satisfy // 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'MyLibrary.UseMethods(Type)'. // The field 'System.Type MyLibrary::type' does not have matching annotations. UseMethods(type); @@ -171,7 +166,7 @@ Similarly, here the problem is that the field `type` is passed into a parameter [DynamicallyAccessedMembers(DynamicallyAccessedMembers.PublicMethods)] static Type type; - static void Baz() + static void InitializeTypeField() { MyLibrary.type = typeof(System.Tuple); } @@ -181,8 +176,10 @@ In this case the trim analysis will simply keep public methods of `System.Tuple` ### Recommendations -In general, try to avoid reflection if possible. When using reflection, limit it in scope so that it is reachable only from a small part of the library. For example, avoid using non-understood patterns in places like static constructors that will result in the warning propagating to all members of the class. +In general, try to avoid reflection if possible. When using reflection, limit it in scope so that it is reachable only from a small part of the library. +- Avoid using non-understood patterns in places like static constructors that will result in the warning propagating to all members of the class. +- Avoid annotating virtual methods or interface methods, which will require all overrides to have matching annotations. - In some cases, you will be able to mechanically propagate warnings through your code without issues. Sometimes this will result in much of your public API being annotated with `RequiresUnreferencedCode`, which is the right thing to do if the library indeed behaves in ways that can't be understood statically by the trim analysis. - In other cases, you might discover that your code uses patterns which can't be expressed in terms of the `DynamicallyAccessedMembers` attributes, even if it only uses reflection to operate on statically-known types. In these cases, you may need to reorganize some of your code to make it follow an analyzable pattern. - Sometimes the existing design of an API will render it mostly trim-incompatible, and you may need to find other ways to accomplish what it is doing. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed. From 8be2b0d2b1d784fb99ccc14b1a0f9086190a913f Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 15 Apr 2021 15:32:12 -0700 Subject: [PATCH 13/41] Add advanced section Which mentions UnconditionalSuppressMessage --- .../preparing-libraries-for-trimming.md | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 12be8c705f8d5..4dd7882444970 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -174,7 +174,7 @@ Similarly, here the problem is that the field `type` is passed into a parameter In this case the trim analysis will simply keep public methods of `System.Tuple`, and will not produce further warnings. -### Recommendations +## Recommendations In general, try to avoid reflection if possible. When using reflection, limit it in scope so that it is reachable only from a small part of the library. @@ -183,3 +183,67 @@ In general, try to avoid reflection if possible. When using reflection, limit it - In some cases, you will be able to mechanically propagate warnings through your code without issues. Sometimes this will result in much of your public API being annotated with `RequiresUnreferencedCode`, which is the right thing to do if the library indeed behaves in ways that can't be understood statically by the trim analysis. - In other cases, you might discover that your code uses patterns which can't be expressed in terms of the `DynamicallyAccessedMembers` attributes, even if it only uses reflection to operate on statically-known types. In these cases, you may need to reorganize some of your code to make it follow an analyzable pattern. - Sometimes the existing design of an API will render it mostly trim-incompatible, and you may need to find other ways to accomplish what it is doing. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed. + +## Resolving warnings for non-analyzable patterns + +You should prefer resolving warnings by expressing the intent of your code using `RequiresUnreferencedCode` and `DynamicallyAccessedMembers` when possible. However, in some cases you may be interested in enabling trimming of a library that uses patterns which can't be expressed with those attributes, or without refactoring existing code. This section describes additional advanced ways to resolve trim analysis warnings. + +> [!WARNING] +> These techniques might break your code if used incorrectly. + +When suppressing warnings, you are responsible for guaranteeing the trim compatibility of your code based on invariants that you know to be true by inspection. Be very careful with these annotations, because if they are incorrect, or if invariants of your code change, they might end up hiding real issues. + +### UnconditionalSuppressMessage + +If the intent of your code can't be expressed with the annotations, but you know that the warning doesn't represent a real issue at runtime, you can suppress the warnings using [`UnconditionalSuppressMessageAttribute`](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.unconditionalsuppressmessageattribute?view=net-5.0). This is similar to `SuppressMessageAttribute`, but it is persisted in IL and respected during trim analysis. For example: + +```csharp +class TypeCollection +{ + Type[] types;u + + // Ensure that only types with ctors are stored in the array + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + public Type this[int i] + { + // warning IL2063: TypeCollection.Item.get: Value returned from method 'TypeCollection.Item.get' + // can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + get => types[i]; + set => types[i] = value; + } +} + +class TypeCreator +{ + TypeCollection types; + + public void CreateType(int i) + { + types[i] = typeof(TypeWithConstructor); + Activator.CreateInstance(types[i]); // No warning! + } +} + +class TypeWithConstructor +{ +} +``` + +Here, the indexer property has been annotated so that the returned `Type` meets the requirements of `CreateInstance`. This already ensures that the `TypeWithConstructor` constructor is kept, and that the call to `CreateInstance` doesn't warn. Furthermore, the indexer setter annotation ensures that any types stored in the `Type[]` have a constructor. However, the analysis isn't able to see this, and still produces a warning for the getter, because it doesn't know that the returned type has its constructor preserved. + +If you are sure that the requirements are met, you can silence this warning by adding `UnconditionalSuppressMessage` to the getter: + +```csharp + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + public Type this[int i] + { + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063", + Justification = "The list only contains types stored through the annotated setter.")] + get => types[i]; + set => types[i] = value; + } +``` + + + + From 5be3f6038cda578b03b6751f8476db84cf8637ea Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 15 Apr 2021 15:35:09 -0700 Subject: [PATCH 14/41] Remove whitespace --- docs/core/deploying/preparing-libraries-for-trimming.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 4dd7882444970..278f10df40403 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -243,7 +243,3 @@ If you are sure that the requirements are met, you can silence this warning by a set => types[i] = value; } ``` - - - - From 926b6dcabef1b563899c5703a61df24ab293ab83 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 07:28:42 -0700 Subject: [PATCH 15/41] PR feedback - Clarify why we need an exe - Improve comments in sample csproj --- .../core/deploying/preparing-libraries-for-trimming.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 278f10df40403..6aa14809ad13b 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -32,7 +32,9 @@ The Roslyn analyzer is useful for a fast feedback cycle with IDE integration, bu ### Showing all warnings -To show all analysis warnings for your library, including warnings about dependencies, create a project like the following that references your library, and publish it with `PublishTrimmed`. +To show all analysis warnings for your library, including warnings about dependencies, create a separate app project like the following that references your library, and publish it with `PublishTrimmed`. + +Publishing a self-contained app ensures that the library is analyzed in a context where its dependencies are available, so that you are alerted if your library uses any code from dependencies that is incompatible with trimming. ```xml @@ -43,13 +45,15 @@ To show all analysis warnings for your library, including warnings about depende linux-x64 true + link - + false + @@ -60,8 +64,6 @@ To show all analysis warnings for your library, including warnings about depende dotnet publish -c Release ``` -- Publishing a self-contained app ensures that the library is analyzed in a context where its dependencies are available, so that you are alerted if your library uses any code from dependencies that is incompatible with trimming. - - `TrimmerRootAssembly` ensures that every part of the library is analyzed. This is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`, which would otherwise let trimming remove the unused library without analyzing it. - `link` ensures that only used parts of dependencies are analyzed. Without this option, you would see warnings originating from _any_ part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "True")]`, including parts that are unused by your library. From 407851e787d68aba447e1096559d537b9b36e2f1 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 07:32:34 -0700 Subject: [PATCH 16/41] More comments --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 6aa14809ad13b..13644a39cc58d 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -53,7 +53,7 @@ Publishing a self-contained app ensures that the library is analyzed in a contex - + From 1fdb5f2f499c665236170133d8be779260c12bda Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 07:34:26 -0700 Subject: [PATCH 17/41] PR feedback Simplify wording --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 13644a39cc58d..6367bc06fad67 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -26,7 +26,7 @@ Ensure you are using the .NET 6 SDK for these steps. They will not work correctl ## Enable Roslyn analyzer -During development, set `true` (in .NET 6+) in your library project. This will not have any effect on the output, but it will enable trim analysis during build via a Roslyn analyzer. +Set `true` (in .NET 6+) in your library project. This will not have any effect on the output, but it will enable trim analysis during build via a Roslyn analyzer. The Roslyn analyzer is useful for a fast feedback cycle with IDE integration, but is currently incomplete. It doesn't cover all trim analysis warnings, but the set of patterns it understands will improve over time to give more complete coverage. The Roslyn analyzer also isn't able to analyze the implementations of reference assemblies that you depend on. It is important to follow the next steps to ensure that your library is fully compatible with trimming. From f65f1a621d8d66fc3aa61f15cc4b7fa260f7ebfb Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:45:21 -0700 Subject: [PATCH 18/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 6367bc06fad67..6bdb0b810f859 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -1,5 +1,5 @@ --- -title: Preparing libraries for trimming +title: Prepare .NET libraries for trimming description: Learn how to prepare libraries for trimming. author: sbomer ms.author: svbomer From 21a1a15018518d071497c7d12fb360d8c01e7cd5 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:45:30 -0700 Subject: [PATCH 19/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 6bdb0b810f859..a960937336994 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -1,6 +1,6 @@ --- title: Prepare .NET libraries for trimming -description: Learn how to prepare libraries for trimming. +description: Learn how to prepare .NET libraries for trimming. author: sbomer ms.author: svbomer ms.date: 08/25/2020 From 2d4842a4a23b4c54764cfec811dd32d1a5e8ce5a Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:45:39 -0700 Subject: [PATCH 20/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index a960937336994..0eb417a81ba46 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -3,7 +3,7 @@ title: Prepare .NET libraries for trimming description: Learn how to prepare .NET libraries for trimming. author: sbomer ms.author: svbomer -ms.date: 08/25/2020 +ms.date: 04/16/2021 --- # Preparing libraries for trimming From 80ccb57f31e9f1ed01b52024eed3b621c4f623eb Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:45:47 -0700 Subject: [PATCH 21/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 0eb417a81ba46..34fb9354bbf79 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -6,7 +6,7 @@ ms.author: svbomer ms.date: 04/16/2021 --- -# Preparing libraries for trimming +# Prepare .NET libraries for trimming ## Trim warnings in apps From 47ed8e97572a4d875d41cccbab10467100c52932 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:47:38 -0700 Subject: [PATCH 22/41] Update docs/core/deploying/trimming-options.md Co-authored-by: David Pine --- docs/core/deploying/trimming-options.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/trimming-options.md b/docs/core/deploying/trimming-options.md index 4958ad9ce74d5..2f895bbe025b7 100644 --- a/docs/core/deploying/trimming-options.md +++ b/docs/core/deploying/trimming-options.md @@ -148,7 +148,7 @@ Individual [warning codes](https://github.com/mono/linker/blob/master/docs/error Don't treat ILLink warnings as errors. This may be useful to avoid turning trim analysis warnings into errors when treating compiler warnings as errors globally. -## Showing detailed warnings +## Show detailed warnings In .NET 6+, trim analysis will produce at most one warning for each assembly that comes from a `PackageReference`, indicating that the assembly's internals are not compatible with trimming. You can also show individual warnings for all assemblies: From acc30eeb3a7fe970062203dc6fe92fadc2679367 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:48:20 -0700 Subject: [PATCH 23/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 34fb9354bbf79..e694f8aeda45b 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -18,7 +18,7 @@ To resolve warnings originating from the app code, jump ahead to the instruction If your app only uses parts of a library that are compatible with trimming, consider [enabling trimming](trimming-options.md#trim-additional-assemblies) of this library if it is not already being trimmed. This will only produce warnings if your app uses problematic parts of the library. (You can also [show detailed warnings](trimming-options.md#showing-detailed-warnings) for the library to see which parts of it are problematic.) -## Enabling library trim warnings +## Enable library trim warnings These instructions show how to enable and resolve static analysis warnings to prepare a library for trimming. Follow these steps if you are authoring a library and either want to proactively make your library trimmable, or have been contacted by app authors who encountered trim warnings from your library. From dd2fd47de385db46d2c631b5a0fddd09d970f4d3 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:48:37 -0700 Subject: [PATCH 24/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index e694f8aeda45b..601d0a6bccace 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -30,7 +30,7 @@ Set `true` (in .NET 6+) in your library The Roslyn analyzer is useful for a fast feedback cycle with IDE integration, but is currently incomplete. It doesn't cover all trim analysis warnings, but the set of patterns it understands will improve over time to give more complete coverage. The Roslyn analyzer also isn't able to analyze the implementations of reference assemblies that you depend on. It is important to follow the next steps to ensure that your library is fully compatible with trimming. -### Showing all warnings +### Show all warnings To show all analysis warnings for your library, including warnings about dependencies, create a separate app project like the following that references your library, and publish it with `PublishTrimmed`. From 783589a0cbb18179ba1f81f6a2a2870a1f3b9daa Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:49:12 -0700 Subject: [PATCH 25/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- .../preparing-libraries-for-trimming.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 601d0a6bccace..d6e79f23da07c 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -151,15 +151,15 @@ Now any calls to `UseMethods` will produce warnings if they pass in values which Here is another example where an unknown `Type` flows into the annotated method parameter, this time from a field: ```csharp - static Type type; +static Type type; - static void UseMethodsHelper() - { - // warning IL2077: MyLibrary.UseMethodsHelper(Type): 'type' argument does not satisfy - // 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'MyLibrary.UseMethods(Type)'. - // The field 'System.Type MyLibrary::type' does not have matching annotations. - UseMethods(type); - } +static void UseMethodsHelper() +{ + // warning IL2077: MyLibrary.UseMethodsHelper(Type): 'type' argument does not satisfy + // 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'MyLibrary.UseMethods(Type)'. + // The field 'System.Type MyLibrary::type' does not have matching annotations. + UseMethods(type); +} ``` Similarly, here the problem is that the field `type` is passed into a parameter with these requinements. You can fix it by adding `DynamicallyAccessedMembers` to the field. This will warn about code that assigns incompatible values to the field instead. Sometimes this process will continue until a public API is annotated, and other times it will end when a concrete type flows into a location with these requirements. For example: From 36f684e3a5c2dab62b124ffda97ff0be07b456d9 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:50:15 -0700 Subject: [PATCH 26/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- docs/core/deploying/preparing-libraries-for-trimming.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index d6e79f23da07c..5ed0305cb8929 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -72,7 +72,8 @@ dotnet publish -c Release You can also follow the same pattern for multiple libraries, adding them all to the same project as `ProjectReference` and `TrimmerRootAssembly` item to see trim analysis warnings for more than one library at a time, but note that this will warn about dependencies if _any_ of the root libraries use a trim-unfriendly API in a dependency. To see warnings that have to do with only a particular library, reference that library only. -Note that the analysis results depend on the implementation details of your dependencies. If you update to a new version of a dependency, this may introduce analysis warnings if the new version added non-understood reflection patterns, even if there were no API changes. In other words, introducing trim analysis warnings to a library is a breaking change when the library is used with `PublishTrimmed`. +> [!NOTE] +> The analysis results depend on the implementation details of your dependencies. If you update to a new version of a dependency, this may introduce analysis warnings if the new version added non-understood reflection patterns, even if there were no API changes. In other words, introducing trim analysis warnings to a library is a breaking change when the library is used with `PublishTrimmed`. ## Resolving trim warnings From 1ad69874f08b658a57fdb3a2aad63fb2298beda2 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:50:26 -0700 Subject: [PATCH 27/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 5ed0305cb8929..18befe26180be 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -75,7 +75,7 @@ You can also follow the same pattern for multiple libraries, adding them all to > [!NOTE] > The analysis results depend on the implementation details of your dependencies. If you update to a new version of a dependency, this may introduce analysis warnings if the new version added non-understood reflection patterns, even if there were no API changes. In other words, introducing trim analysis warnings to a library is a breaking change when the library is used with `PublishTrimmed`. -## Resolving trim warnings +## Resolve trim warnings The above steps will produce warnings about code that may cause problems when used in a trimmed app. Here are a few examples of the most common kinds of warnings you may encounter, with recommendations for fixing them. From bb7efadebd67f952cf31a2b05e349d7885dad83b Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:50:35 -0700 Subject: [PATCH 28/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 18befe26180be..7c394076601c6 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -14,7 +14,7 @@ When publishing an app, `PublishTrimmed` will produce trim analysis [warnings](t You will encounter detailed warnings originating from your own code and `ProjectReference` dependencies. You may also see warnings like `warning IL2104: Assembly 'SomeAssembly' produced trim warnings` for `PackageReference` libraries. This means that the library contained patterns which are not guaranteed to work in the context of the trimmed app, and may result in a broken app. Consider contacting the author to see if the library can be annotated for trimming. -To resolve warnings originating from the app code, jump ahead to the instructions on [resolving trim warnings](#resolving-trim-warnings). If you are interested in making your own `ProjectReference` libraries trim friendly, follow the instructions to [enable library trim warnings](#enabling-library-trim-warnings). +To resolve warnings originating from the app code, see [resolving trim warnings](#resolve-trim-warnings). If you are interested in making your own `ProjectReference` libraries trim friendly, follow the instructions to [enable library trim warnings](#enable-library-trim-warnings). If your app only uses parts of a library that are compatible with trimming, consider [enabling trimming](trimming-options.md#trim-additional-assemblies) of this library if it is not already being trimmed. This will only produce warnings if your app uses problematic parts of the library. (You can also [show detailed warnings](trimming-options.md#showing-detailed-warnings) for the library to see which parts of it are problematic.) From 86d8f820ce184363a14e9d45c50e428b98c78ab2 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:50:43 -0700 Subject: [PATCH 29/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 7c394076601c6..1cdaefed6d0e6 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -12,7 +12,7 @@ ms.date: 04/16/2021 When publishing an app, `PublishTrimmed` will produce trim analysis [warnings](trimming-options.md#analysis-warnings) (in .NET 6+) for patterns that are not statically understood to be compatible with trimming, including patterns in your code and in dependencies. -You will encounter detailed warnings originating from your own code and `ProjectReference` dependencies. You may also see warnings like `warning IL2104: Assembly 'SomeAssembly' produced trim warnings` for `PackageReference` libraries. This means that the library contained patterns which are not guaranteed to work in the context of the trimmed app, and may result in a broken app. Consider contacting the author to see if the library can be annotated for trimming. +You will encounter detailed warnings originating from your own code and `ProjectReference` dependencies. You may also see warnings like `warning IL2104: Assembly 'SomeAssembly' produced trim warnings` for `PackageReference` libraries. This warning means that the library contained patterns which are not guaranteed to work in the context of the trimmed app, and may result in a broken app. Consider contacting the author to see if the library can be annotated for trimming. To resolve warnings originating from the app code, see [resolving trim warnings](#resolve-trim-warnings). If you are interested in making your own `ProjectReference` libraries trim friendly, follow the instructions to [enable library trim warnings](#enable-library-trim-warnings). From 65da4a29e7e78adca7a1359b06f48d15e8118dbc Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:51:02 -0700 Subject: [PATCH 30/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- .../deploying/preparing-libraries-for-trimming.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 1cdaefed6d0e6..e529ceb5284b5 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -138,13 +138,13 @@ public class MyLibrary Here, `UseMethods` is calling a reflection method which has a [`DynamicallyAccessedMembers`](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.dynamicallyaccessedmembersattribute?view=net-5.0) requirement. The requirement states that the type's public methods are available. In this case, you can fix this by adding the same requirement to the parameter of `UseMethods`. ```csharp - static void UseMethods( - // State the requirement in the UseMethods parameter. - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] - Type type) - { - // ... - } +static void UseMethods( + // State the requirement in the UseMethods parameter. + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] + Type type) +{ + // ... +} ``` Now any calls to `UseMethods` will produce warnings if they pass in values which don't satisfy the `PublicMethods` requirement. Like with `RequiresUnreferencedCode`, once you have bubbled up such warnings to public APIs, you are done. From 3a9e3a82e0621a14044de521b25f2bd918a3dcf2 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:51:51 -0700 Subject: [PATCH 31/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index e529ceb5284b5..c3b481868a212 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -10,7 +10,7 @@ ms.date: 04/16/2021 ## Trim warnings in apps -When publishing an app, `PublishTrimmed` will produce trim analysis [warnings](trimming-options.md#analysis-warnings) (in .NET 6+) for patterns that are not statically understood to be compatible with trimming, including patterns in your code and in dependencies. +In .NET 6+, when publishing an app, the `PublishTrimmed` project file element will produce trim analysis [warnings](trimming-options.md#analysis-warnings) for patterns that are not statically understood to be compatible with trimming, including patterns in your code and in dependencies. You will encounter detailed warnings originating from your own code and `ProjectReference` dependencies. You may also see warnings like `warning IL2104: Assembly 'SomeAssembly' produced trim warnings` for `PackageReference` libraries. This warning means that the library contained patterns which are not guaranteed to work in the context of the trimmed app, and may result in a broken app. Consider contacting the author to see if the library can be annotated for trimming. From cba163908bc2fd92b7709feb970064ca5abfeb3b Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:52:07 -0700 Subject: [PATCH 32/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- .../deploying/preparing-libraries-for-trimming.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index c3b481868a212..330f7fedf0ddd 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -105,12 +105,12 @@ This means the library calls a method which has explicitly been annotated as inc https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.requiresunreferencedcodeattribute?view=net-5.0). To get rid of the warning, consider whether `Method` needs to call `DynamicBehavior` to do its job. If so, annotate the caller `Method` with `RequiresUnreferencedCode` as well; this will "bubble up" the warning so that callers of `Method` get a warning instead: ```csharp - // Warn for calls to Method, but not for Method's call to DynamicBehavior. - [RequiresUnreferencedCode("Calls DynamicBehavior.")] - public static void Method() - { - DynamicBehavior(); // OK. Doesn't warn now. - } +// Warn for calls to Method, but not for Method's call to DynamicBehavior. +[RequiresUnreferencedCode("Calls DynamicBehavior.")] +public static void Method() +{ + DynamicBehavior(); // OK. Doesn't warn now. +} ``` Once you have "bubbled up" the attribute all the way to public APIs (so that these warnings are produced only for public methods, if at all), you are done. Apps which call your library will now get warnings if they call those public APIs, but these will no longer produce warnings like `IL2104: Assembly 'MyLibrary' produced trim warnings`. From bfc95c644207de3702f27c6ff958ab0cf08e9a5a Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:52:24 -0700 Subject: [PATCH 33/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- .../deploying/preparing-libraries-for-trimming.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 330f7fedf0ddd..9cd5854bd5d99 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -166,13 +166,13 @@ static void UseMethodsHelper() Similarly, here the problem is that the field `type` is passed into a parameter with these requinements. You can fix it by adding `DynamicallyAccessedMembers` to the field. This will warn about code that assigns incompatible values to the field instead. Sometimes this process will continue until a public API is annotated, and other times it will end when a concrete type flows into a location with these requirements. For example: ```csharp - [DynamicallyAccessedMembers(DynamicallyAccessedMembers.PublicMethods)] - static Type type; +[DynamicallyAccessedMembers(DynamicallyAccessedMembers.PublicMethods)] +static Type type; - static void InitializeTypeField() - { - MyLibrary.type = typeof(System.Tuple); - } +static void InitializeTypeField() +{ + MyLibrary.type = typeof(System.Tuple); +} ``` In this case the trim analysis will simply keep public methods of `System.Tuple`, and will not produce further warnings. From ec938047d00dd704ed89bc4e8b1e3caf9d535c37 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:52:39 -0700 Subject: [PATCH 34/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- docs/core/deploying/preparing-libraries-for-trimming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 9cd5854bd5d99..6164b2c10bba4 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -187,7 +187,7 @@ In general, try to avoid reflection if possible. When using reflection, limit it - In other cases, you might discover that your code uses patterns which can't be expressed in terms of the `DynamicallyAccessedMembers` attributes, even if it only uses reflection to operate on statically-known types. In these cases, you may need to reorganize some of your code to make it follow an analyzable pattern. - Sometimes the existing design of an API will render it mostly trim-incompatible, and you may need to find other ways to accomplish what it is doing. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed. -## Resolving warnings for non-analyzable patterns +## Resolve warnings for non-analyzable patterns You should prefer resolving warnings by expressing the intent of your code using `RequiresUnreferencedCode` and `DynamicallyAccessedMembers` when possible. However, in some cases you may be interested in enabling trimming of a library that uses patterns which can't be expressed with those attributes, or without refactoring existing code. This section describes additional advanced ways to resolve trim analysis warnings. From 01f9bfb115b277a9d76113e3243d70c3b4ef826a Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:53:54 -0700 Subject: [PATCH 35/41] Update docs/core/deploying/preparing-libraries-for-trimming.md Co-authored-by: David Pine --- .../preparing-libraries-for-trimming.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 6164b2c10bba4..02e07bad4cd85 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -237,12 +237,12 @@ Here, the indexer property has been annotated so that the returned `Type` meets If you are sure that the requirements are met, you can silence this warning by adding `UnconditionalSuppressMessage` to the getter: ```csharp - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] - public Type this[int i] - { - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063", - Justification = "The list only contains types stored through the annotated setter.")] - get => types[i]; - set => types[i] = value; - } +[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] +public Type this[int i] +{ + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063", + Justification = "The list only contains types stored through the annotated setter.")] + get => types[i]; + set => types[i] = value; +} ``` From 57402e78103556c46362eb1d85bcd943a070e1c3 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 14:54:09 -0700 Subject: [PATCH 36/41] Update docs/core/deploying/trimming-options.md Co-authored-by: David Pine --- docs/core/deploying/trimming-options.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/trimming-options.md b/docs/core/deploying/trimming-options.md index 2f895bbe025b7..8e438cdd33226 100644 --- a/docs/core/deploying/trimming-options.md +++ b/docs/core/deploying/trimming-options.md @@ -158,7 +158,7 @@ In .NET 6+, trim analysis will produce at most one warning for each assembly tha The defaults show detailed warnings for the project assembly and `ProjectReference`s. `` can also be set as metadata on an [individual assembly](#trimmed-assemblies) to control the warning behavior for that assembly only. -## Removing symbols +## Remove symbols Symbols will normally be trimmed to match the trimmed assemblies. You can also remove all symbols: From 35bdcfd86e6efb4c43c0eba0b0cd9752354e2ba8 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 15:33:01 -0700 Subject: [PATCH 37/41] Add intro and fix links --- docs/core/deploying/preparing-libraries-for-trimming.md | 6 ++++-- docs/core/deploying/trimming-options.md | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/preparing-libraries-for-trimming.md index 02e07bad4cd85..022d24a8d126e 100644 --- a/docs/core/deploying/preparing-libraries-for-trimming.md +++ b/docs/core/deploying/preparing-libraries-for-trimming.md @@ -8,15 +8,17 @@ ms.date: 04/16/2021 # Prepare .NET libraries for trimming +The .NET SDK makes it possible to reduce the size of self-contained apps by [trimming](trim-self-contained.md), removing unused code from the app and its dependencies. Not all code is compatible with trimming, so .NET 6 provides trim analysis [warnings](trimming-options.md#analysis-warnings) to detect patterns that may break trimmed apps. This document describes how to prepare libraries for trimming with the aid of these warnings, including recommendations for fixing some common cases. + ## Trim warnings in apps -In .NET 6+, when publishing an app, the `PublishTrimmed` project file element will produce trim analysis [warnings](trimming-options.md#analysis-warnings) for patterns that are not statically understood to be compatible with trimming, including patterns in your code and in dependencies. +In .NET 6+, when publishing an app, the `PublishTrimmed` project file element will produce trim analysis warnings for patterns that are not statically understood to be compatible with trimming, including patterns in your code and in dependencies. You will encounter detailed warnings originating from your own code and `ProjectReference` dependencies. You may also see warnings like `warning IL2104: Assembly 'SomeAssembly' produced trim warnings` for `PackageReference` libraries. This warning means that the library contained patterns which are not guaranteed to work in the context of the trimmed app, and may result in a broken app. Consider contacting the author to see if the library can be annotated for trimming. To resolve warnings originating from the app code, see [resolving trim warnings](#resolve-trim-warnings). If you are interested in making your own `ProjectReference` libraries trim friendly, follow the instructions to [enable library trim warnings](#enable-library-trim-warnings). -If your app only uses parts of a library that are compatible with trimming, consider [enabling trimming](trimming-options.md#trim-additional-assemblies) of this library if it is not already being trimmed. This will only produce warnings if your app uses problematic parts of the library. (You can also [show detailed warnings](trimming-options.md#showing-detailed-warnings) for the library to see which parts of it are problematic.) +If your app only uses parts of a library that are compatible with trimming, consider [enabling trimming](trimming-options.md#trim-additional-assemblies) of this library if it is not already being trimmed. This will only produce warnings if your app uses problematic parts of the library. (You can also [show detailed warnings](trimming-options.md#show-detailed-warnings) for the library to see which parts of it are problematic.) ## Enable library trim warnings diff --git a/docs/core/deploying/trimming-options.md b/docs/core/deploying/trimming-options.md index 8e438cdd33226..e2525c3bef738 100644 --- a/docs/core/deploying/trimming-options.md +++ b/docs/core/deploying/trimming-options.md @@ -80,7 +80,7 @@ Do not add or remove items to/from `ManagedAssemblyToLink`, because the SDK comp - `True` or `False` - Control whether to show [single warnings](#showing-detailed-warnings) for this assembly. + Control whether to show [single warnings](#show-detailed-warnings) for this assembly. ## Root assemblies From 1d45b64aeebd33a062271f183934cfaf9ddd6a88 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 16 Apr 2021 15:38:05 -0700 Subject: [PATCH 38/41] Rename file to match title --- ...raries-for-trimming.md => prepare-libraries-for-trimming.md} | 0 docs/fundamentals/toc.yml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/core/deploying/{preparing-libraries-for-trimming.md => prepare-libraries-for-trimming.md} (100%) diff --git a/docs/core/deploying/preparing-libraries-for-trimming.md b/docs/core/deploying/prepare-libraries-for-trimming.md similarity index 100% rename from docs/core/deploying/preparing-libraries-for-trimming.md rename to docs/core/deploying/prepare-libraries-for-trimming.md diff --git a/docs/fundamentals/toc.yml b/docs/fundamentals/toc.yml index af8704076c066..9474c4095086a 100644 --- a/docs/fundamentals/toc.yml +++ b/docs/fundamentals/toc.yml @@ -1368,7 +1368,7 @@ items: - name: Options href: ../core/deploying/trimming-options.md - name: Trimming libraries - href: ../core/deploying/preparing-libraries-for-trimming.md + href: ../core/deploying/prepare-libraries-for-trimming.md - name: Runtime package store href: ../core/deploying/runtime-store.md - name: Runtime Identifier (RID) catalog From cc33ea1da4af4a446ce11423bc334dcc2511bfd0 Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 19 Apr 2021 08:11:31 -0500 Subject: [PATCH 39/41] Update trimming-options.md --- docs/core/deploying/trimming-options.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/trimming-options.md b/docs/core/deploying/trimming-options.md index e2525c3bef738..4e40ef6cdef83 100644 --- a/docs/core/deploying/trimming-options.md +++ b/docs/core/deploying/trimming-options.md @@ -174,7 +174,7 @@ Several feature areas of the framework libraries come with linker directives tha - `false` - Remove code that enables better debugging experiences. This will also [remove symbols](#removing-symbols). + Remove code that enables better debugging experiences. This will also [remove symbols](#remove-symbols). - `false` From 0de2989b447760f0720f6f8bc467038fb13aa349 Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 19 Apr 2021 08:15:21 -0500 Subject: [PATCH 40/41] Apply suggestions from code review --- docs/core/deploying/prepare-libraries-for-trimming.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/core/deploying/prepare-libraries-for-trimming.md b/docs/core/deploying/prepare-libraries-for-trimming.md index 022d24a8d126e..9631964879d01 100644 --- a/docs/core/deploying/prepare-libraries-for-trimming.md +++ b/docs/core/deploying/prepare-libraries-for-trimming.md @@ -104,7 +104,7 @@ public class MyLibrary ``` This means the library calls a method which has explicitly been annotated as incompatible with trimming, using [`RequiresUnreferencedCodeAttribute`]( -https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.requiresunreferencedcodeattribute?view=net-5.0). To get rid of the warning, consider whether `Method` needs to call `DynamicBehavior` to do its job. If so, annotate the caller `Method` with `RequiresUnreferencedCode` as well; this will "bubble up" the warning so that callers of `Method` get a warning instead: +https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.requiresunreferencedcodeattribute?view=net-5.0&preserve-view=true). To get rid of the warning, consider whether `Method` needs to call `DynamicBehavior` to do its job. If so, annotate the caller `Method` with `RequiresUnreferencedCode` as well; this will "bubble up" the warning so that callers of `Method` get a warning instead: ```csharp // Warn for calls to Method, but not for Method's call to DynamicBehavior. @@ -137,7 +137,7 @@ public class MyLibrary } ``` -Here, `UseMethods` is calling a reflection method which has a [`DynamicallyAccessedMembers`](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.dynamicallyaccessedmembersattribute?view=net-5.0) requirement. The requirement states that the type's public methods are available. In this case, you can fix this by adding the same requirement to the parameter of `UseMethods`. +Here, `UseMethods` is calling a reflection method which has a [`DynamicallyAccessedMembers`](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.dynamicallyaccessedmembersattribute?view=net-5.0&preserve-view=true) requirement. The requirement states that the type's public methods are available. In this case, you can fix this by adding the same requirement to the parameter of `UseMethods`. ```csharp static void UseMethods( @@ -200,7 +200,7 @@ When suppressing warnings, you are responsible for guaranteeing the trim compati ### UnconditionalSuppressMessage -If the intent of your code can't be expressed with the annotations, but you know that the warning doesn't represent a real issue at runtime, you can suppress the warnings using [`UnconditionalSuppressMessageAttribute`](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.unconditionalsuppressmessageattribute?view=net-5.0). This is similar to `SuppressMessageAttribute`, but it is persisted in IL and respected during trim analysis. For example: +If the intent of your code can't be expressed with the annotations, but you know that the warning doesn't represent a real issue at runtime, you can suppress the warnings using [`UnconditionalSuppressMessageAttribute`](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.unconditionalsuppressmessageattribute?view=net-5.0&preserve-view=true). This is similar to `SuppressMessageAttribute`, but it is persisted in IL and respected during trim analysis. For example: ```csharp class TypeCollection From 496671c34ae725f2dd03284d4d24773ca520ea52 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 19 Apr 2021 09:21:59 -0700 Subject: [PATCH 41/41] PR feedback - Don't require un-suppressing warnings, as this is now implied by TrimmerDefaultAction=link: https://github.com/dotnet/sdk/pull/16865 - Clarify why publishing an app is necessary for library warnings --- docs/core/deploying/prepare-libraries-for-trimming.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/core/deploying/prepare-libraries-for-trimming.md b/docs/core/deploying/prepare-libraries-for-trimming.md index 9631964879d01..9066614debf10 100644 --- a/docs/core/deploying/prepare-libraries-for-trimming.md +++ b/docs/core/deploying/prepare-libraries-for-trimming.md @@ -36,7 +36,7 @@ The Roslyn analyzer is useful for a fast feedback cycle with IDE integration, bu To show all analysis warnings for your library, including warnings about dependencies, create a separate app project like the following that references your library, and publish it with `PublishTrimmed`. -Publishing a self-contained app ensures that the library is analyzed in a context where its dependencies are available, so that you are alerted if your library uses any code from dependencies that is incompatible with trimming. +The extra step of creating an app project just to get complete warnings for a library is necessary because the implementations of dependencies are not generally available during `dotnet build`, and reference assemblies don't contain enough information to determine whether they are compatible with trimming. Publishing a self-contained app ensures that the library is analyzed in a context where its dependencies are available, so that you are alerted if your library uses any code from dependencies that could break a trimmed app. ```xml @@ -49,8 +49,6 @@ Publishing a self-contained app ensures that the library is analyzed in a contex true link - - false @@ -70,8 +68,6 @@ dotnet publish -c Release - `link` ensures that only used parts of dependencies are analyzed. Without this option, you would see warnings originating from _any_ part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "True")]`, including parts that are unused by your library. -- `false` is implied by `PublishTrimmed` in the .NET SDK. It is only needed if the app targets form factors like Android where the trim analysis warnings are disabled by default. Consult the documentation for your SDK. - You can also follow the same pattern for multiple libraries, adding them all to the same project as `ProjectReference` and `TrimmerRootAssembly` item to see trim analysis warnings for more than one library at a time, but note that this will warn about dependencies if _any_ of the root libraries use a trim-unfriendly API in a dependency. To see warnings that have to do with only a particular library, reference that library only. > [!NOTE]