Skip to content

Roslyn Analyzer and Code Fix for repeated StringName implicit allocations #106096

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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

myblindy
Copy link

@myblindy myblindy commented May 5, 2025

Implicit StringName allocations from strings are fine, however they can hide the allocations from the user. This is even more important when they get repeatedly called in tight loops(*). Related issues: #106066 and #105750

This analyzer issues a warning when these constant StringName allocations happen in any kind of loop:
image

Note that only constant strings (as the compiler sees them, so it includes constant string concatenation, etc) are considered, something like this is still fine:
image

It will offer to automatically fix it by creating a static readonly StringName field in the class and replace all allocations with it:
image

It will also automatically reuse an existing such field, if one exists:
image

(*) Note: right now it only considers actual C# loops, it does not consider implicit frame loops like the ready or process functions. It would be easy to add if it's needed, however that would flag every single StringName implicit conversion like in input checks. There would be a performance gain from it, but.. it makes the Godot API look kind of shaky if it's needed to such a high degree.

Also note: This is fully compatible with the #106066 proposal, as it checks the semantic model for implicit conversions. So if a string overload is present and the compiler successfully binds the string to it there will be no implicit conversion to trigger the analyzer:
image vs image

Copy link
Member

@raulsntos raulsntos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for contributing to the .NET module!

The .NET team was discussing something like this the other day. We regret making the conversion between StringName and String implicit and think it should've been explicit instead. However, given how much it would break to change this now, we think an analyzer and code fixer would be a great alternative.

We were thinking of reporting a diagnostic for all cases of implicit conversion, and not just in loops. Checking if the implicit conversion is inside a loop doesn't seem worth the effort and likely misses complex scenarios.

We think the noise would be acceptable because in most cases there's a preferable alternative that we'd want to encourage users to use instead (such as PropertyName, MethodName, or SignalName). It would also be easy to disable the warning with .editorconfig, #pragma warning disable, or an explicit cast (which also conveys that the conversion was intentional). The code fixer would also make it easy to fix and can be applied in batch.

@myblindy
Copy link
Author

myblindy commented May 7, 2025

@raulsntos so just to recap, you’re saying that this should warn on every single implicit conversion from string to StringName, correct?

That is a trivial change, I’ll take care of it tomorrow morning!

@beicause
Copy link
Contributor

beicause commented May 7, 2025

I agree this PR is a good solution. I will close #106066. Although #106066 is compatible with this PR, it would suppress the warnings. Caching StringName is still the best.

@myblindy
Copy link
Author

myblindy commented May 7, 2025

I agree this PR is a good solution. I will close #106066. Although #106066 is compatible with this PR, it would suppress the warnings. Caching StringName is still the best.

I mean, it doesn’t have to disable the warnings. Slap a framework attribute on the new string parameters (like [StringNameParameter] or something) and I can add it to the list of things it checks and auto-fixes.

@beicause
Copy link
Contributor

beicause commented May 7, 2025

I'm not familiar with Roslyn Analyzer, but #106066 still isn't worth adding the complexity. In places where performance matters, there's no reason to use strings instead of constructing StringName in advance.

By the way, the warnings and auto fixes should also be provided for NodePath.

@myblindy
Copy link
Author

myblindy commented May 7, 2025

I'm not familiar with Roslyn Analyzer, but #106066 still isn't worth adding the complexity. In places where performance matters, there's no reason to use strings instead of constructing StringName in advance.

I strongly disagree with that. In fact I believe that the StringName abstraction should be hidden from the user completely, like it is in GDScript (and it would be with the implicit construction operator). We only care about it here because it's written in a way that is very inefficient, and that is an implementation detail.

Godot C#'s closest competitor is Unity, and they don't require you to create cache variables just to check key/gamepad inputs, for example. Simplicity is king, as long as it doesn't tank framerates.

@myblindy
Copy link
Author

myblindy commented May 7, 2025

@raulsntos I updated it as discussed, now it will trigger warnings on every implicit StringName construction, and it will auto-correct as many as possible by caching the variable as long as the string used to construct it can be evaluated at compile time. Dynamic implicit StringName instances remain highlighted as warnings, but have no code fix available.

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

Successfully merging this pull request may close these issues.

4 participants