Intro to Roslyn Series, Part 1

Haritha Mohan,compilerdesigntool

Recently I have been working on a tool to help generate documentation for our SDK, providing the end user with easy-to-access docs via Intellisense in the IDE.

So I embarked on this journey by initially using Mono.cecil (opens in a new tab) and reflection to iterate through our SDK assembly to identify members and provide the appropriate docs. I had used this library in the past before and it provides some neat capabilities. And…it was (...and potentially would have) gotten the job done in this case too. But I was running into an (well, a few) issue with this initial approach.

Typically such docs via intellisense are generated by using triple-slash docs (opens in a new tab) in the source code repository. But when there’s thousands of API to document, adding such comments can bloat our source code significantly.

So when looking at the workflow for how such intellisense support is generally developed: For a given member:

  1. Add ///
  2. The compiler picks up on this /// comment, generates the necessary element in the XML doc
  3. The IDE uses the XML as a reference to provide the user with the appropriate docs via intellisense upon usage.

We can optimize by eliminating step 1 essentially and jumping right into step 2. But…how?

Let’s take a look at the bridge between steps 1 and 2: how do we go from a triple slash comment to generating the appropriate XML element?

Can we short circuit this and eliminate the need for the triple slash comment to begin with and somehow programmatically generate the necessary XML element for a given member since that's what the IDE is using as a point of launch to generate the desired intellisense?

Spoiler: yes!...and also simultaneously the reason for the migration from Mono.cecil to Roslyn for our choice of library being used for the assembly walkthrough.

So the bridge in question between steps 1 and 2 in the aforementioned flow is handled by the one and only…Roslyn

Photo

…this?

oops wait wrong roslyn...

Photo

ah, there we go, Roslyn: the C# compiler (opens in a new tab).

Anyways, back to the compiler and its magic! So for an member that looks like this in the source code:

Photo

It generates a XML element that looks like this:

Photo

The key thing to pay attention to is the ID of the member. This is what ties all the pieces together from the source code to the XML to the intellisense end result. This is where I came to a crossroads with my journey with Mono.cecil ending and Roslyn beginning.

The Roslyn APIs offer a wide variety of powerful tools to select from in handling source code. Tools like semantic models, symbols, and in this case what we are really interested in, access to the documentation comment ID (opens in a new tab) generated for a symbol.

So although I had come somewhat along in my approach of using Mono.cecil and generating XML elements with the appropriate docs, I was at a crossroads of continuing down a road that was familiar yet somewhat outdated and not the most adept for the job or taking the road not yet wandered and utilizing the power of Roslyn to bring this tool to life.

In this case, it was worth backtracking a couple steps for the overall end goal of crafting a more robust tool that will be able to handle the asks of the assembly walkthrough and necessary workflow more elegantly and efficiently.

So now by making the switch, the tool could now:

So TLDR: sometimes you can craft a really intricate and well-thought out solution but with also employing the right tools, you can elevate your solution from good to great.

© Haritha Mohan.RSS