[Guest Post] Better refactoring for Unity projects using .NET analyzers
This post was authored by guest blogger Shreya Pandit, an intern on the Visual Studio Tools for Unity team and published by the team on her behalf.
My name is Shreya Pandit, and I am an undergraduate student majoring in Computer Science and Cognitive Science at MIT. I had the incredible opportunity to intern with the Tools for Unity Team this past month. I worked specifically on the Microsoft Analyzers for Unity Project, an open-source project on GitHub. This project offers code suggestions and suppresses warnings for developers in Unity to improve their code correctness and performance. Starting the internship with basic knowledge in C# and Unity, I initially focused on familiarizing myself with the language as well as the gaming environment. I was then ready to shift my attention to the Analyzer project where I would create a variety of analyzers based off community suggestions in the GitHub repository.
The Microsoft Analyzers for Unity Project intends to provide developers with Unity specific suggestions to improve their code. This tool is offered through Visual Studio, a powerful IDE, and relies on the .NET Compiler Platform, Roslyn. The compiler uses an API to inspect and analyze code as the developer is programming which is useful to check the syntax and semantics. Adding a new analyzer enables Roslyn to check for a particular code pattern, and if detected, it will recommend a code fix specified by the analyzer. For example, one of the analyzers identifies empty
MonoBehaviour methods, such as
Start(), and recommends deleting the method to improve the code efficiency.
Example: Creating a New Analyzer
During my internship, I created a variety of analyzers to detect different code patterns. I will walk through one of the analyzers that I recently added to break down the process and provide tips along the way.
Identify Problem and Solution
One of the analyzers that I added came from a community suggestion in the GitHub repository. It improved the code performance by minimizing the number of times Unity class “transform” would be accessed. The goal was to replace code assignments such as:
transform.position = newPosition; transform.rotation = newRotation;
The project repository offers an easy-to-follow README to set-up the project. After downloading the appropriate packages, generate files for a new analyzer by following the section heading: “Creating a New Analyzer”. All that is needed is a descriptive title, and in this example, I named the analyzer
Detect Code Pattern
Once the new analyzer was created, I found it easiest to create a few test cases in the test file. This ensured that the analyzer found the generic pattern as opposed to a single specific case. Next, I wanted to create a method that would be able to detect the code pattern identified in the problem. For this example, I looked for two consecutive lines that assigned a new position and new rotation.
Visual Studio in Windows offers a neat feature called the Syntax Visualizer. The window enables users to open any C# code file and examine the current working tree from a class declaration to a method operation. To find this window, go to View / Other Windows / Syntax Visualizer. Here is an example of the syntax tree displayed in the visualizer.
Based off the syntax tree, I needed to detect two subsequent Expression Statements of Assignment Expressions where one accessed the position property of transform and the other accessed the rotation property. I tested the analysis of the code pattern by running my test cases and checking for unexpected diagnostic errors.
Suggest Code Fix
The Syntax Visualizer can similarly be used to understand the syntax of the target expression. I started by constructing the new line with the appropriate syntax and was able to replace and delete the nodes that were originally detected. The code for this can be seen below and found in the analyzer’s file on GitHub.
var invocation = InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, baseExpression, IdentifierName("SetPositionAndRotation"))) .WithArgumentList(argList) .WithLeadingTrivia(trivia); var documentEditor = await DocumentEditor.CreateAsync(document, cancellationToken); documentEditor.RemoveNode(assignmentExpression.Parent, SyntaxRemoveOptions.KeepNoTrivia); documentEditor.ReplaceNode(nextAssignmentExpression, invocation); return documentEditor.GetChangedDocument();
All the test cases should pass when the code fix is completed correctly.
Submit a pull request
After following these steps and adding documentation, the analyzer is ready to be reviewed and merged to the code base. Submit a pull request and checkout the final analyzer. Here is a link to my PR, and an example of the below the Set Position and Rotation analyzer in action below.
Contribute to the Project
I have really enjoyed working on the Microsoft Analyzers for Unity project with this group over the past few weeks. Even with limited knowledge in Unity and C#, I was quickly able get accustomed to the environment and start creating new analyzers and suppressors. This is a great self-contained project for people with different coding backgrounds. If you are looking to learn more about Visual Studio and Unity or contribute to an open-source project, creating an analyzer requires a low barrier to entry for high impact. I have learned a lot in the process and want to give a special thanks to my manager JB Evain and the rest of the team for all their support. I am confident that they would appreciate your suggestions and PR submissions to continue improving the developer experience in Unity.
Visit the GitHub repository to get started!