Property Explosion with Roslyn API

Conclusion

Yip, we’ll start at the end. This article aims to show the powers of Roslyn and hopefully inspire some great ideas to help grow the already Massive eco-system of free tooling for Visual Studio (VS).

The final product is this life changing VS Refactoring tool, called Property Explosion

ExtensionsAndUpdates

Go give it a try, in Visual Studio go to Tools -> Extensions and Updates -> Search for Property Explosion in the online section -> Download and Install -> (Restart VS when done)

Now open up any C# project, click on a property (either Auto-property or Full-property) and Hit Ctrl + . and you’ll get a suggestion to either Explode the property (make it full) or Crunch it (convert to Auto property).

CrunchProperty

Life Changing Stuff!  If you’re interested in how we got here, read on.

This article will discuss, installation, touch on high level overview of code and VSIX deployment. My source code is available on GitHub (see links at the bottom).

Now the Beginning

Now we’ve seen the future and taken away from the dramatic climax (like watching The Village for the second time).

So, What is Roslyn? As quickly mentioned in a previous article, Roslyn is an open-source implementation of the C# / VB.Net compilers. But one of the key features of is the API it exposes allowing us to create analytical and refactoring tools. We’ll be using the Roslyn API to build a VS Refactoring tool.

Installation

You’ll need Visual Studio 2015 and the Roslyn SDK (If you don’t have the SDK installed, you can install it directly through VS, which is pretty neat).

  • Open up Visual Studio 2015
  • File -> New Project
  • Under Visual C# go to Extensibility.

If you have installed Roslyn SDK:

  • Click on Code Refactoring (VSIX) Project and OK 

If not:

  • Choose Install Visual Studio Extensibility Tools directly out of Visual Studio and hit OK

VS_install_roslyn

  • Then Download the .NET Compiler Platform SDK hit OK and download it

VS_downloadCompiler

  • Now you can choose Code Refactoring (VSIX) Project and OK 

Getting started

Now that you’ve created a Code Refactoring project, you’ll see there’s some default plumbing set up.

There are 2 projects created.

  1. Portable class library, which holds the refactoring entry point and code logic.
  2. VSIX project, which only holds a vsixmanifest file and references the class library.

Make sure the .VSIX project is set as a startup project. A .VSIX file is basically a Visual Studio extensions installation file. This is what get’s deployed to the Visual Studio Gallery enabling users to download the tool.

You should now be able to hit F5 and debug the project as it. This will open up another instance of VS 2015, with the VSIX installed and attaches the debugger to the new VS instance.

  • Open up a project (or create a new Console App).
  • Now click on the class and hit Ctrl + .
  • You’ll see a suggestion pop up to reverse the class name e.g. Program becomes margorP.

To debug and step through the code and see what’s happening is really easy:

  • Put a breakpoint in the ComputeRefactoringsAsync method in the CodeRefactoringProvider class
  • Now in the new VS instance, click on a class name again and hit Ctrl + . and the breakpoint will be hit.

How does code refactoring work?

  1. User hits Ctrl + . and VS will look for installed VSIX tools
  2. The Roslyn API will call the Entry Point in custom code (CodeRefactoringProvider)
  3. Custom code makes decisions on which Code Actions to register.
  4. User sees a little Context Menu pop up with Code Action(s) available
  5. User clicks on the Code Action, and code is refactored.

Property Explosion Code

It’s a bit out of scope to go through each piece of the Property Explosion code. We will however take a high level look at what was done and why.

Here’s the PropertyExplosion Repository on GitHub. Click Download to Zip, unzip and open up the solution

So now in the context of the Property Explosion code, a user hits Ctrl + . and the Entry Point in our custom code gets hit.

Registering Code Action(s)

First thing is we do at Entry Point is to check if we’re dealing with a property and if so, do we have an Auto Property or a Full Property? If we have an Auto Property, we need to register the Explode Code Action, which can expand the property. Similarly, if we have a Full property we register the Crunch Code Action, to collapse property to Auto Property.

Now we need to rewrite our code

We could simply do some code refactoring directly in the code action method, but it seems the preferred scalable approach is to use a Syntax Rewriter. In our project, we’ve got the PropertyCollapser and PropertyExploder rewriters. Syntax rewriters work on the Visitor Design Pattern. It’s a tedious one to get used to if you’ve never worked with it before, but in the Syntax Rewriter, you can see how and why it’s very useful.

What that means in our case is that we call visit on a Node and then the each element in the Syntax Tree will be traversed and “visited”. If the current element being visited is one that we care about (for example the property in question), then we can override the Rewriter’s Visit method for the specific node type and manipulate the Syntax Node.


public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax propertyDeclaration)
{
  if (propertyDeclaration == this._fullProperty)
  {
    //... Create a new property ...
    return newProperty;
  }

  return base.VisitPropertyDeclaration(propertyDeclaration);
}

See the code above, where we override the VisitPropertyDeclaration method. This method will be hit for every property that is traversed in the Syntax Tree. Since we only care about one specific property in question, we do a check. Is this the property we’re busy refactoring? If Yes, then we go on to build a new property and return it.

That’s easy enough, replacing an existing Node. But how do we add a new node with the Visitor Pattern? Let’s take adding a new field. We check our visit method if we’re busy with the Property’s Parent, if so, we create a new field, insert it and return the “updated” parent. Easy as that.

Use the existing code as reference, put some breakpoints down and see how the Visit methods get called and used to refactor Nodes.

Now we simply return the new root (which is the one modified by the Rewriters) to the Document and our code is successfully refactored.

Deployment

Once you’re happy with the refactoring tool, it’s time to deploy. Deployment is really easy.

  1. Check that you’re happy with the config in the vsixmanifest file
  2. Change VS build type to Release, and build the solution.
  3. Go to the bin\release folder and you’ll find a .VSIX file.
  4. Login or Register at Visual Studio Gallery
  5. Click Upload and Upload the .VSIX file
  6. Once Uploaded, make sure to click Publish and Your tool is available for download immediately from VS Gallery or directly from VS (Tools -> Extensions and Updates).

Things to consider

1) “Rewriting” code is more complicated than a simple statement

We need to think like a compiler rather than developer. It’s crucial to understand that we work with these 3 things to build up code: Syntax Nodes, Syntax Tokens and Trivia.

Let’s take this statement for example:



string myString = "Hello World";


That’s as easy as it gets. We see a simple one liner. The compiler sees Nodes, Tokens and Trivia:

Visualizer_HelloWorld

It’s very demoralizing realising the complexity of a simple statement. But it needn’t be. If you’ve installed the .NET Compiler Platform SDK, go to View –> Other Windows –> Roslyn Syntax Visualizer. This Window is a life saver as it demonstrates your current code’s Syntax Tree. DON’T BE A HERO, USE THE VISUALIZER!!!

If you’re wondering how something should be expressed, code it, click on it and the Roslyn Syntax Visualizer will show you a granular break down of its Nodes, Tokens and Trivia.

Nodes

  • These are the main building block of the syntax tree (the blue ones in the above image).
  • Statements, Expressions, Clauses, Declarations etc.

Tokens 

  • These are almost like little extras. They cannot be a parent to other Nodes or Tokens (the green ones)
  • Keywords, Literals, Semi-colons etc.

Trivia

  • These are there for formatting purposes and don’t affect code directly (the white/grey ones)
  • Comments, Whitespaces, Regions etc.

2) How to find a Member

The 2 ways of finding something is done via the Syntax Tree or Semantic Model.

Syntax Tree

  • Not much extra info on a Node (e.g. can’t determine if and where a member is referenced)
  • Optimized for performance.

Semantic Model

  • Rich with extra compile time info (e.g. references to a member)
  • Much slower than the Syntax Tree because it often triggers a compilation of code

Try always use Syntax Tree unless you can’t, then use Semantic Model. Semantic Model is very powerful and is an important feature of the Roslyn API.

3) Treat the vsixmanifest file with care

I managed to mess up my vsixmanifest file. I was able to build the project, deploy it, download & install it but nothing happened. I thought the fault was in the code, so I tried debugging, which stopped working as well. No logs, no error messages, nothing works any more.

You’ll probably want to configure the compatibly of VS and .NET framework versions that your tool can run on. So much like any config file, take care when making changes.

If you’ve messed it up, create a new Refactoring Code Project and use the fresh vsixmanifest file as a reference to fix the existing one.

That’s it…

That’s it from a high level overview for building a code refactoring tool using the Roslyn API. I hope it provided you with an idea to get started. Please feel free to download my code, step through it, use it, improve it, abuse it or sell it for millions.

Some links…

Advertisements

One thought on “Property Explosion with Roslyn API

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s