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 :
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
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
then displaying the error using RegisterCompilationEndActionWhy?
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 errorPlease 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
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
so in this example, basically, the line 13 of
Request should throw an error because the Test event was triggered in a non-generic versionI 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
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 errornot a problem
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
by a single type, you probably mean in the same file?
No
I mean single type
Types can be spread over multiple files via
partialthis is what I do rn btw. Previously I was collecting the whole tree on a
RegisterSyntaxNodeAction which is kinda... expensive with GetSemanticModel
(and one file can have multiple types)
I don't really get it, do you have a small example? 🤔
Of...
partial?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
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
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 🤔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
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
Oh, it's possible, as you've done it. It's just not the best live experience
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? 😃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