-
Notifications
You must be signed in to change notification settings - Fork 127
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
Opaque warnings for unsupported features without managed callers #2004
Comments
This is related to a request from @eerhardt which is to allow We could couple that with such warnings being visible "through" the single-warning mechanism. And we could also make them less about the "call" and more about the feature in the messages. |
Another problem with the current behavior is that the following program produces no trim warnings: class Program {
[RequiresUnreferencedCode("")]
public static void Main() {
// do something with Reflection
}
} I think this should warn, but at the same time we probably shouldn't warn when annotating public APIs of a library. |
Technically you're right, but I won't loose any sleep if we don't 😉 |
I don't think I ever officially wrote it up. Just discussed offline with you. |
How would people feel if we were to disable warnings collapsing if the IsTrimmable metadata is set on a library? The reasoning is that if someone sets IsTrimmable, they reviewed/annotated the library. Any leftover warnings are either a library bug, or intentional places like this one. Or have another attribute that says "collapsing warnings from this library would not serve the user". |
What about the case where the library is used with runtime/SDK/dependency version which had a fix that introduced a new warning? |
The way I think about collapsing, it is designed to prevent warnings which "come from" implementation details of a library. Startup hook logically isn't an implementation detail - it's a feature provided by the library with a user-facing option to enable it - and so the warning shouldn't "come from" the library internals. If we can find a way to express this, the no-collapse behavior would fall out of it. One way would be to put the warning in the SDK - if PublishTrimmed == true and StartupHookSupport == true, produce a warning. Then it is individually suppressible, and isn't collapsed. But I don't like this solution because it isn't tied to the attribute at all. Also, when I suggested tying warning collapsing to "IsTrimmable" a while ago, one concern was that trimming everything would produce undesired warnings. Collapsing them for IsTrimmable assembly metadata but not for the IsTrimmable MSBuild metadata would mean that the two have subtly different behavior. |
The SDK solution is problematic. For startup hook it might work, but what if it's something which the app doesn't use - then it should not get a warning (like ResourceManager warnings for example). |
For features which are activated by calls from managed code, this isn't a problem to begin with since we just "blame" the caller, if I'm not missing something. Bubbling up RUC or DAM to the public API will prevent warnings from the implementing library. If the app calls it the warning won't be collapsed, and if it doesn't, there won't be any warning. |
True - unless it's hidden behind some other API - for example:
If you turn on BinaryFormatter - you will get a warning - but from inside ResourceManager - not from the public API surface. |
This is technically not true. We introduced a separate feature switch in ResourceManager ( BinaryFormatter's API is marked as RUC, so if we didn't have these extra feature switches, these libraries would still be warning, even though BinaryFormatter is turned off. |
Coming back to this issue, I agree something needs to be changed with the current "collapsing" behavior. We have a few warnings left in the dotnet/runtime libraries (in files named One example I just ran into is in So in this case, I don't want the warning to be collapsed and saying |
I'm a bit worried about actionability of the warning - "hey, you're using JsonObject with I can't think of a good solution - modulo just annotating the API in Microsoft.CSharp, because all those |
That's (roughly) the same experience of the original warning in this issue - StartupHookProvider. The warning can't tell you where a startup hook might break with a trimmed app - just that using it with trimming doesn't always work.
Agreed that the developer will get warnings about all |
That one has a more natural place to issue the warning like Sven suggested above - the SDK. It's where we decide startup hook support should be disabled when trimming and where we could warn if someone still turns it on. The fix can be spelled out in the warning message (just don't enable it in your csproj). |
I took a closer look at how we handled this for resources and now I understand @vitek-karas' point that it's not so different from the StartupHook case. I personally find this mind-boggling and would like to solve it differently. 😄 Let's say we have a feature void Library() {
LibraryImpl();
if (Feature.IsSupported)
UseFeature(); // warns
}
[RUC("Feature")]
void UseFeature() {} Is it ok to suppress this warning with I would argue yes - the author of If we emit a warning that "blames" the library, it will look like the library author hasn't done the work to annotate their library, when in fact the library is perfectly "safe" with the default linker settings. So I see two rough directions we could go for solving this:
I think going forward we will want to distinguish between guarded and unguarded calls to RUC methods, and it might be worth designing it so that it can be extended to support checking calls to any feature code (including features that don't require unreferenced code) as mentioned in #1723. |
I don't really like option (2) above, mostly because:
|
I didn't think this was an issue unless you consider feature switches - it sounds like we are looking at the problem slightly differently. Is this an example of the situation you're concerned about? class LibraryA {
static void Method() {
LibraryB.DoStuff();
}
} class LibraryB {
[RUC("DoStuff is not compatible with trimming")]
static void DoStuff() { }
} When building an app that references
I would consider that to be by design since we don't want to give detailed warnings for unannotated third-party libraries. If the app called
I agree it better belongs in the library. Thinking some more about it I actually don't think we need to put it in the SDK. We just need some way to tell which feature settings are trim-incompatible - all that's missing is a link between RUC and the feature switches. If we combine this with approach 1., say by giving RUC a
This way the warnings are also limited to the RUC code that's actually reachable from the app. This would give the following behavior:
|
Note that this doesn't address the part of the issue about individually-suppressable warnings for different RUC attributes. It seems like that requires lifting the Roslyn restriction that warning codes are statically known (if we want to suppress them by warning code). If we are ok with using a different suppression mechanism, we could add a linker-specific way to suppress warnings by feature name - or by subcategory as @mateoatr suggested - I just think the extra info we add to RUC attributes needs to specify the feature switch. This also wouldn't give libraries a way to suppress the feature switch warnings via attributes, but I think that makes sense because these warnings would be "global". |
There are 2 concrete situations that I'm thinking about right now:
|
To distill the Json case, here's a simple example with the same issue (the warning will show up whenever public interface IFoo {
void Method();
}
public class MyFoo : IFoo {
public void Method() {
RUC(); // warning
}
[RUC]
void RUC() {}
} There are a few options for dealing with the warning:
What will we recommend to customers who hit this issue in their own code? |
Thanks for writing these down Sven! The problem is really that we don't have a good spot where to put the blame and what action should the user take if they hit the warning. There are some parallels with the ResourceReader support scenario, which we solved with approach 4 from Sven's list. That one was a piece of problematic code that is always included. We put it behind a feature switch and added RUC annotation that mentions the feature switch. The only problem with that approach is the warning collapsing if someone goes and turns the feature back on. |
The expectation for now is that this is relatively rare - meaning that there will be only a handful of RUC attributes for which we need "new behavior". So I don't see a big need to make this super easy to understand for somebody added the RUC attribute. I personally don't see it as a problem that these would not show up in Roslyn analyzer. All the cases I've seen so far as effectively global problems. Feature switches are by definition global (specified by the app, not any library) - even if the Roslyn analyzer for the app would see these, it would not have a good place to report the warning from. The case with the interfaces is also global by definition and Roslyn analyzer has no chance of detecting this (outside of the special case of all of it happening in one assembly). Whichever solution we decide to use should:
My current favorite (but we would have to try it) is basically 5 from the above list. It is not a super robust solution, but it should work. I would rather try this with some reasonably simple solution and only when we see this becoming a bigger problem, try to design some robust, probably more explicit solution. |
FYI for completeness - here's one more candidate where leaving a warning in the library might make sense: dotnet/runtime#52046 (comment) The scenario here is an implementation of |
By design, turning on startup hook support produces a warning. However, the warning shown by default is not helpful.
First, it is collapsed:(fixed by #2087)If you uncollapse it,the warning mentions implementation details of the startup hook:Only the last part is useful to the app developer. Note that there is a dependency from the XML descriptor -> ProcessStartupHook -> [RUC] CallStartupHook, and the warning is produced for the call to CallStartupHook.
I believe we need a way to mark some APIs such that they:
don't get collapsed by defaultFor startup hook, I think it should only say "The StartupHookSupport feature switch has been enabled for this app which is being trimmed. Startup hook code is not observable by the trimmer and so required assemblies, types and members may be removed."
Startup hooks happen to not have public APIs, but the native hosting APIs will have a similar problem, and they do have public UnmanagedCallersOnly APIs. The current approach will show warnings like "public API calls internal method with RequiresUnreferencedCode" - it would be better not to mention the internal APIs.
@LakshanF
The text was updated successfully, but these errors were encountered: