Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Does trim analyzer emit warnings for the inaccessible code? #3239

Open
voroninp opened this issue Nov 29, 2023 · 8 comments
Open

Comments

@voroninp
Copy link

I want to share data contracts between backend and frontend, including API definition.

I use Refit and I see it generates private classes which are not used in assembly anywhere. These classes are instantiated with reflection. So there's no chance they are going to be ever rooted by static code.

When I set data contract library as trim compatible my BlazorWasm application fails to start because Refit cannot find the generated implementation. Obviously 🤣

Should not linker produce a warning when it detects an isolated set of private dependencies which are 100% will be inaccessible by any non-reflection code?

@sbomer
Copy link
Member

sbomer commented Nov 29, 2023

The linker should produce a warning that points at the reflection code, assuming the reflection code isn't written in a way that can be statically analyzed (with DynamicallyAccessedMembersAttribute annotations). Having inaccessible/dead code isn't a problem on its own; the problem is the reflection.

Blazor wasm disables trim warnings out of the box (see dotnet/aspnetcore#44845). To see whether the linker is producing such a warning you can set <SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>.

@voroninp
Copy link
Author

The WTF of the day. Thanks.

@vitek-karas
Copy link
Member

The trimmer will not warn about "unused" code - that happens all the time. The trimmer should produce a warning at the point where the library is trying to access this code via reflection. In your case I would expect warnings from the refit library, but not from other libraries which are just "using it".

There's nothing wrong with having "dead" code in your app - if it's not needed at runtime, nothing cares. The problem is if the app needs to access things which the trimmer can't figure out. And so the trimmer "thinks" it's dead code, but the app is trying to use it. The only way to correctly detect this is to look at the place where the app is "looking" for this code.

@sbomer
Copy link
Member

sbomer commented Nov 29, 2023

@voroninp I tried adding a PackageReference to Refit, and I see this warning in the publish output (not in the build output):

warning IL2104: Assembly 'Refit' produced trim warnings.

You can show more details by setting <TrimmerSingleWarn>false</TrimmerSingleWarn> (docs). With this I get:

/_/Refit/RefitSettings.cs(197,81): Trim analysis warning IL2075: Refit.DefaultFormUrlEncodedParameterFormatter.<>c__DisplayClass1_0.<Format>b__1(String): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicFields', 'DynamicallyAccessedMemberTypes.PublicNestedTypes', 'DynamicallyAccessedMemberTypes.PublicProperties', 'DynamicallyAccessedMemberTypes.PublicEvents' in call to 'System.Type.GetMember(String)'. The return value of method 'System.Object.GetType()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
/_/Refit/RefitSettings.cs(164,85): Trim analysis warning IL2075: Refit.DefaultUrlParameterFormatter.<>c__DisplayClass1_0.<Format>b__1(String): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicFields', 'DynamicallyAccessedMemberTypes.PublicNestedTypes', 'DynamicallyAccessedMemberTypes.PublicProperties', 'DynamicallyAccessedMemberTypes.PublicEvents' in call to 'System.Type.GetMember(String)'. The return value of method 'System.Object.GetType()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
/_/Refit/RequestBuilderImplementation.cs(142,26): Trim analysis warning IL2060: Refit.RequestBuilderImplementation.<>c__DisplayClass11_0.<CloseGenericMethodIfNeeded>b__0(CloseGenericMethodKey): Call to 'System.Reflection.MethodInfo.MakeGenericMethod(Type[])' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method.
/_/Refit/SystemTextJsonContentSerializer.cs(56,13): Trim analysis warning IL2026: Refit.SystemTextJsonContentSerializer.<FromHttpContentAsync>d__4<T>.MoveNext(): Using member 'System.Net.Http.Json.HttpContentJsonExtensions.ReadFromJsonAsync<T>(HttpContent, JsonSerializerOptions, CancellationToken)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.
/_/Refit/FormValueMultimap.cs(138,13): Trim analysis warning IL2070: Refit.FormValueMultimap.GetProperties(Type): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'System.Type.GetProperties(BindingFlags)'. The parameter 'type' of method 'Refit.FormValueMultimap.GetProperties(Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
/_/Refit/SystemTextJsonContentSerializer.cs(108,13): Trim analysis warning IL2026: Refit.ObjectToInferredTypesConverter.Write(Utf8JsonWriter, Object, JsonSerializerOptions): Using member 'System.Text.Json.JsonSerializer.Serialize(Utf8JsonWriter, Object, Type, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.
/_/Refit/RequestBuilderImplementation.cs(40,13): Trim analysis warning IL2070: Refit.RequestBuilderImplementation.RequestBuilderImplementation(Type, RefitSettings): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'refitInterfaceType' of method 'Refit.RequestBuilderImplementation.RequestBuilderImplementation(Type, RefitSettings)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
/_/Refit/RequestBuilderImplementation.cs(67,13): Trim analysis warning IL2070: Refit.RequestBuilderImplementation.AddInterfaceHttpMethods(Type, Dictionary<String,List<RestMethodInfoInternal>>): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The parameter 'interfaceType' of method 'Refit.RequestBuilderImplementation.AddInterfaceHttpMethods(Type, Dictionary<String,List<RestMethodInfoInternal>>)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
/_/Refit/RequestBuilderImplementation.cs(360,13): Trim analysis warning IL2075: Refit.RequestBuilderImplementation.BuildQueryMap(Object, String, RestMethodParameterInfo): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'System.Type.GetProperties(BindingFlags)'. The return value of method 'System.Object.GetType()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
/_/Refit/RequestBuilderImplementation.cs(932,17): Trim analysis warning IL2075: Refit.RequestBuilderImplementation.DoNotConvertToQueryMap(Object): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The return value of method 'System.Object.GetType()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
/_/Refit/RequestBuilderImplementation.cs(932,17): Trim analysis warning IL2065: Refit.RequestBuilderImplementation.DoNotConvertToQueryMap(Object): Value passed to implicit 'this' parameter of method 'System.Type.GetInterfaces()' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.
/_/Refit/RestMethodInfo.cs(201,13): Trim analysis warning IL2075: Refit.RestMethodInfoInternal.GetParameterProperties(ParameterInfo): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'System.Type.GetProperties(BindingFlags)'. The return value of method 'System.Reflection.ParameterInfo.ParameterType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
/_/Refit/RestMethodInfo.cs(424,13): Trim analysis warning IL2075: Refit.RestMethodInfoInternal.ParseHeaders(MethodInfo): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The return value of method 'System.Reflection.MemberInfo.DeclaringType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
/_/Refit/RestService.cs(78,13): Trim analysis warning IL2072: Refit.RestService.For(Type, HttpClient, IRequestBuilder): 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'System.Activator.CreateInstance(Type, Object[])'. The return value of method 'System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue>.GetOrAdd(ConcurrentDictionary<TKey,TValue>.TKey, Func<ConcurrentDictionary<TKey,TValue>.TKey,ConcurrentDictionary<TKey,TValue>.TValue>)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
/_/Refit/RestService.cs(163,13): Trim analysis warning IL2057: Refit.RestService.GetGeneratedType(Type): Unrecognized value passed to the parameter 'typeName' of method 'System.Type.GetType(String)'. It's not possible to guarantee the availability of the target type.
/_/Refit/SystemTextJsonContentSerializer.cs(48,13): Trim analysis warning IL2026: Refit.SystemTextJsonContentSerializer.ToHttpContent<T>(T): Using member 'System.Net.Http.Json.JsonContent.Create<T>(T, MediaTypeHeaderValue, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.
/_/Refit/ValidationApiException.cs(43,17): Trim analysis warning IL2026: Refit.ValidationApiException.Create(ApiException): Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.

@voroninp
Copy link
Author

@sbomer , yes, it looks like I am mistakenly awaiting trim warnings also on build, not only on publish.

@MichalStrehovsky
Copy link
Member

FWIW, trimmability of refit is tracked in reactiveui/refit#1389. It is not currently compatible with trimming.

@voroninp
Copy link
Author

@sbomer , is it possible to trigger full analysis as a step of build process without publishing?

@sbomer
Copy link
Member

sbomer commented Nov 30, 2023

No, the Roslyn analyzer that runs during build doesn't have insight into the implementation of referenced assemblies, and ILLink is set up to run during publish because that's the point at which all implementation assemblies become available to the toolchain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants