C
C#•2w ago
Keyde

Rider - Custom Roslyn Analyzer

Hello! I wrote a custom Analyzer for Roslyn to show some errors on Rider which works quite well. The goal is to "simply" detect if a method called EventManager.Attach(EventHook.MyEvent) was called and if it is : we look for a EventManager.TriggerEvent(EventHook.MyEvent) to check if the generic version was properly used or not (because there is a non-generic version and a generic one) It works properly to check cross-files and show errors on Rider. However, this line triggers a warning (RS1030 :
var model = compilation.GetSemanticModel(tree);
var model = compilation.GetSemanticModel(tree);
so I tried migrating to a "shared" version with RegisterCompilationStartAction , RegisterOperationAction with 2 pass (to collects TriggerEvent functions and Attach functions) then displaying the error using RegisterCompilationEndAction While it works well on build, it doesn't show anything on Rider (Rider 2025). Shouldn't Roslyn in Rider do multiple pass to trigger it once a while and then showing errors?
GitHub
roslyn-analyzers/src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnal...
Contribute to dotnet/roslyn-analyzers development by creating an account on GitHub.
23 Replies
Aaron
Aaron•2w ago
things do not run CompilationEnd at design time (aka normal usage) it would be extremely expensive to be essentially doing full compilations all the time doing a full build is really the only way those actions get run
333fred
333fred•2w ago
then displaying the error using RegisterCompilationEndAction
Why?
Keyde
KeydeOP•2w ago
Since the calls are in different files, I must do a cross-check file. I followed what said the rule to migrate RegisterOperationAction and if my understanding is good : I must wait the end of the "collect" to get all methods and then trigger an error
333fred
333fred•2w ago
Please show a full example of what you're trying to detect Because I don't know why this would be the case Likely you are just misunderstanding what RS1030 is telling you to do Your description sounds similar to https://github.com/dotnet/sdk/blob/main/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Usage/PreferGenericOverloads.cs, which needs no compendaction
Keyde
KeydeOP•2w ago
I have two methods for the event manager with generics : - Attach(EventHook.SomeEvent) - TriggerEvent(EventHook.SomeEvent) - Attach<T>(EventHook.SomeEvent, Action callback) - TriggerEvent<T>(EventHook.SomeEvent, Action callback) My goal is to detect if an Attach(EventHook.SomeEvent) method was called and a TriggerEvent<T>(EventHook.SomeEvent, ...) of the same event was invoked, the Attach method must be flagged
No description
Keyde
KeydeOP•2w ago
so in this example, basically, the line 13 of Request should throw an error because the Test event was triggered in a non-generic version
333fred
333fred•2w ago
I see. Then yes, CompEnd is required, and it will not run IDEs due to the cost. Just to confirm some things: * These will always exist in the same project, right? You won't have Attach in project A and Trigger in project B? * Is there no way you can just remove the non-generic versions? Also note that CompEnd means you can't really write a fixer for the error
Keyde
KeydeOP•2w ago
These will always exist in the same project, right? You won't have Attach in project A and Trigger in project B?
yep never ever.
Is there no way you can just remove the non-generic versions?
don't think so. It'd require to pass a default payload or do a "bridge" method which I don't really like. In fact it's also for me to create some analyzers a bit more complicated than just checking some method names or what
Also note that CompEnd means you can't really write a fixer for the error
not a problem
333fred
333fred•2w ago
If you were able to require these calls to be done inside a single type, then you could get live IDE diagnostics using SymbolStart/End
Keyde
KeydeOP•2w ago
by a single type, you probably mean in the same file?
333fred
333fred•2w ago
No I mean single type Types can be spread over multiple files via partial
Keyde
KeydeOP•2w ago
this is what I do rn btw. Previously I was collecting the whole tree on a RegisterSyntaxNodeAction which is kinda... expensive with GetSemanticModel
No description
Aaron
Aaron•2w ago
(and one file can have multiple types)
Keyde
KeydeOP•2w ago
I don't really get it, do you have a small example? 🤔
333fred
333fred•2w ago
Of... partial?
Keyde
KeydeOP•2w ago
ok I see.. I think it's kinda not possible in my case : most of my calls would be called in a class extending MonoBehaviour (from Unity) Also, wouldn't it become a mess fast? code base is pretty heavy rn, got 100+ TriggerEvent calls
333fred
333fred•2w ago
I don't know your architecture, so I don't know whether it would become a mess. I was just offering an option that would keep live IDE diagnostics if you could adopt it Not saying that you should or even can Very possible you can't
Keyde
KeydeOP•2w ago
Yeah that's a good idea I would keep in mind it could still be useful one day. I tried to search some native analyzers that do cross-file checks but didn't really found some examples. Is this case really unusual? The only kind of analyzers I'd think of is Unused xxx but I think it lies inside a Rider plugin 🤔
333fred
333fred•2w ago
Is this case really unusual?
Yes. Whether that's more due to it simply being impossible to efficiently tool, or because most analyzers naturally tend to be local to a single block, it's hard to say
Keyde
KeydeOP•2w ago
since the RS1030 gives some insight on how to replace "GetSemanticModel" about using some "sharedModel" I though it'd still be possible to do so
333fred
333fred•2w ago
Oh, it's possible, as you've done it. It's just not the best live experience
Keyde
KeydeOP•2w ago
so if I summarize : - either you have live diags but you live with a GetSemanticModel really expensive - either you do it in a RegisterCompilationEndAction and you have the diag only after the build right? 😃
333fred
333fred•2w ago
Bullet 1 likely also has some latent correctness issues where things don't get rerun as you expect them to and live diagnostics don't go away when you fix the issue

Did you find this page helpful?