Creating Your First Code Refactoring in Visual Studio 2015
One of the great new extensibility features of Visual Studio 2015 is the ability to create refactorings. This allows you to put an action in the Quick Actions menu to provide the user a quick change to the code they are working on. First, you need to install the Visual Studio Extensibility Templates installed in your instance of Visual Studio. You can install this from the Tools->Extensions and Updates menu inside Visual Studio.
Once you have the templates installed, you can create a new refactoring as a new project. Select the Extensibility tab from the new project dialog and create a new Code Refactoring (VSIX) project.
Creating this project will create a refactoring that will give you the option to reverse the name of any type declaration. So you can just run the project, select any type declaration and hit your quick actions key (Ctrl
.
by default) and you will see the Reverse type name action available.
Now that we see that it works, let's look more into how it works. Every code refactoring overrides the ComputeRefactoringsAsync
method. Inside this method, you compute the nodes in the syntax tree on which you want to provide refactoring options. Looking at the refactoring that reverses type names, it starts by finding the node from the SyntaxTree.
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
// Find the node at the selection.
var node = root.FindNode(context.Span);
Next, it checks the type of the node to see if it is a TypeDeclarationSyntax
. If not, it will simply abort the refactoring registration.
// Only offer a refactoring if the selected node is a type declaration node.
var typeDecl = node as TypeDeclarationSyntax;
if (typeDecl == null)
{
return;
}
Finally, it will register a refactoring using the RegisterRefactoring
on the CodeRefactoringContext
. It registers a delegate that returns a Task<Solution>
, which updates the solution with refactored code.
// For any type declaration node, create a code action to reverse the identifier text.
var action = CodeAction.Create("Reverse type name", c => ReverseTypeNameAsync(context.Document, typeDecl, c));
// Register this code action.
context.RegisterRefactoring(action);
Doing this is enough to get the refactoring to appear in the quick actions dialog, but to actually get it to do something, we need to dig into the ReverseTypeNameAsync
method.
This method starts by computing the newly refactored name for the node
// Produce a reversed version of the type declaration's identifier token.
var identifierToken = typeDecl.Identifier;
var newName = new string(identifierToken.Text.ToCharArray().Reverse().ToArray());
Next it finds the symbol that represents the node in the semantic model, so it can properly rename the symbol across the solution.
// Get the symbol representing the type to be renamed.
var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
var typeSymbol = semanticModel.GetDeclaredSymbol(typeDecl, cancellationToken);
Finally, it creates a new solution (remember these objects are immutable) with the renamed symbol. This is done using the Renamer
object from the Microsoft.CodeAnalysis.Rename
namespace. This object takes care of all of the heavy lifting of renaming an object and ensuring that all references in the solution are properly renamed.
// Produce a new solution that has all references to that type renamed, including the declaration.
var originalSolution = document.Project.Solution;
var optionSet = originalSolution.Workspace.Options;
var newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, typeSymbol, newName, optionSet, cancellationToken).ConfigureAwait(false);
// Return the new solution with the now-uppercase type name.
return newSolution;
That's all there is to it. As you can see, creating a refactoring in Visual Studio 2015 is a very easy task and gives you a lot of control in providing quick fixes to code. You can use this in a myriad of ways to make you and your team more productive and more consistent when using Visual Studio 2015.