A collection of code-quality analyzers based on the Roslyn compiler platform. This project aims to ensure code-quality as you type it in your editor rather than having to do this as a separate build-step. By performing static analysis while you're writing code, certain convention violations and hidden pitfalls can be avoided as early in the process as possible.
Keep in mind that this project is under active development. If you encounter bugs, let us know!
What is an analyzer exactly?
With the release of Visual Studio 2015 RC, we also received the pretty much final implementation of the Diagnostics implementation. This SDK allows us to create our own diagnostics to help us write proper code that’s being verified against those rules in real-time: you don’t have to perform the verification at a separate build-step. What’s more is that we can combine that with a code fix: a shortcut integrated in Visual Studio that provides us a solution to what we determine to be a problem.
This might sound a little abstract but if you’ve been using Visual Studio (and/or Resharper) then you know what I mean: have you ever written your classname as class rather than Class? This is a violation of the C# naming conventions and visual studio will warn you about it and provide you a quickfix to turn it into a proper capitalized word. This is exactly the behaviour we can create and which is integrated seemlessly in Visual Studio.
Full text available on my blog.
What is available?
Currently these diagnostics are implemented:
|Arithmetic||VSD0045||The operands of a divisive expression are both integers and result in an implicit rounding.|
|Async||VSD0001||Asynchronous methods should end with the -Async suffix.|
|Async||VSD0064||Async methods should return a
|Attributes||VSD0002||An attribute should not have an empty argument list.|
|Attributes||VSD0003||Gives an enum the
|Exceptions||VSD0009||Verifies whether an
|Exceptions||VSD0010||Warns when an exception catch block is empty.|
|Exceptions||VSD0011||Warns when an exception is rethrown in a way that it loses the stacktrace.|
|Exceptions||VSD0012||Verifies whether a try-catch block does not defer all exception handling to a single
|Exceptions||VSD0052||An exception is thrown from an implicit operator.|
|Exceptions||VSD0053||An exception is thrown from a property getter.|
|Exceptions||VSD0054||An exception is thrown from a static constructor.|
|Exceptions||VSD0055||An exception is thrown from a finally block.|
|Exceptions||VSD0056||An exception is thrown from an equality operator.|
|Exceptions||VSD0057||An exception is thrown from a
|Exceptions||VSD0058||An exception is thrown from a finalizer method.|
|Exceptions||VSD0059||An exception is thrown from a
|Exceptions||VSD0060||An exception is thrown from an
|General||VSD0014||Changes a cast expression to
|General||VSD0015||A boolean expression comparing to
|General||VSD0016||A boolean expression comparing to
|General||VSD0017||The conditional operator shouldn't return redundant default options.|
|General||VSD0018||The conditional operator shouldn't return redundant inverted default options.|
|General||VSD0019||The condition is a constant (false) and thus unnecessary.|
|General||VSD0020||The condition is a constant (true) and thus unnecessary.|
|General||VSD0021||Inserts the default access modifier for a declaration.|
|General||VSD0022||Detects usage of the
|General||VSD0023||Requires braces for
|General||VSD0025||Implements the most common configuration of naming conventions.|
|General||VSD0029||Simplify the expression using an expression-bodied member.|
|General||VSD0030||A constructor is the same as a default constructor and can be removed.|
|General||VSD0033||Use the built-in type alias instead of the concrete type.|
|General||VSD0044||Add cases for missing enum members.|
|General||VSD0043||An instance of type
|General||VSD0047||Implement elementary methods for a type used in a collection.|
|General||VSD0048||A property with a private setter can become a read-only property instead.|
|General||VSD0066||Recursively using an overloaded operator.|
|General||VSD0068||Warns when using
|Strings||VSD0034||Replaces an empty string literal with the more expressive
|Strings||VSD0035||Orders the arguments of a
|Structs||VSD0036||Warns when a struct replaces
|Structs||VSD0050||Structs should implement
|Tests||VSD0037||A test method should not end with -Test.|
|Tests||VSD0038||Verifies whether a test method has the
|Tests||VSD0062||A method might be missing a test attribute.|
How do I use this?
Simply head over to NuGet and install it! If you don't immediately find it: make sure you're also looking through the NuGet V2 package source.
Can I request diagnostics?
Yes, you can! Create an issue and we'll take a look at your proposal.
What if I don't like a diagnostic?
Every diagnostic can be turned off for a single line or for the entire project. At most, you will have to ignore the diagnostic once. For this reason every diagnostic is turned on by default. In order to do so, right click on 'Analyzers' under your references and select 'Open Active Rule Set'. This presents you with the following window to configure which diagnostics should be turned on and their default severity. If you wish to do so, you can change the severity to a more strict or more forgiving setting.
What's on the roadmap?
Most things are filed as an issue so if you want the complete picture -- head over there. However in broad terms:
- Supporting more C# 6 features to ease the transition
- Implement diagnostics aimed at removing unused code
- Create a website that gives more detailed information
- Add user-configurable settings for each diagnostic
- Introduce a Visual Studio extension so it doesn't have to be tied to the project
- Introduce a command-line tool so it isn't tied to a Visual Studio instance
Can I contribute?
Definitely! Take a look at the open issues and see if there's anything that interests you. Submit your pull request and we'll take a look at it as soon as possible.
If you think you're going to make larger changes than a single implementation then we would ask you to get in contact with us first so we can discuss it and prevent unneeded work.
Where can I find more information about every diagnostic?
Release 2.0.0 will come with a website where we document every diagnostic including reasoning behind its implementation choices. In the meantime you can take a look at the tests that belong to each diagnostic to see what exact scenarios we have accounted for.
How can I get in contact?
You're always free to open an issue but if you would like something more direct you can drop by in the StackExchange chat channel where the main contributors reside or send an email to firstname.lastname@example.org.