Skip to content

Commit

Permalink
Merge pull request #409 from Vannevelj/develop
Browse files Browse the repository at this point in the history
release v1.9.3
  • Loading branch information
Vannevelj committed Mar 1, 2016
2 parents 1900e88 + 60229a9 commit 888ec96
Show file tree
Hide file tree
Showing 139 changed files with 26,962 additions and 3,074 deletions.
90 changes: 67 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# VSDiagnostics
A collection of code-quality analyzers based on the new Roslyn 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. Likewise it also tries to help avoid some common pitfalls.

<img src="https://cloud.githubusercontent.com/assets/2777107/7789534/a06db792-0264-11e5-955f-11cbf3261d4f.gif" />
<img src="https://cloud.githubusercontent.com/assets/2777107/12633986/2e05fc66-c576-11e5-92a2-3c192f2f0d89.gif" />

[Get it from NuGet!](https://www.nuget.org/packages/VSDiagnostics/)

Expand All @@ -22,27 +22,49 @@ Full text available on [my blog](http://www.vannevel.net/2015/05/03/getting-star

Currently these diagnostics are implemented:

| Category | Name | Description | Analyzer | Code Fix |
|:-:|:-:|:-:|:-:|:-:|
| Exceptions | EmptyArgumentException | Guards against using an `ArgumentException` without specifying which argument. | Yes | No |
| Exceptions | SingleGeneralException | Guards against using a catch-all clause. | Yes | No |
| Exceptions | CatchNullReferenceException | Guards against catching a NullReferenceException. | Yes | No |
| Exceptions | ArgumentExceptionWithNameofOperator | `ArgumentException` and its subclasses should use `nameof()` when they refer to a method parameter. | Yes | Yes |
| Exceptions | RethrowExceptionWithoutLosingStacktrace | Warns when an exception is rethrown in a way that it loses the stacktrace. | Yes | Yes |
| Exceptions | EmptyCatchClause | Warns when an exception catch block is empty. | Yes | No |
| Async | AsyncMethodWithoutAsyncSuffix | Asynchronous methods should end with -Async. | Yes | Yes |
| Strings | ReplaceEmptyStringWithStringDotEmpty | Use `string.Empty` instead of `""`. | Yes | Yes |
| Tests | TestMethodWithoutPublicModifier | Change the access modifier to `public` for all methods annotated as test. Supports NUnit, MSTest and xUnit.net. | Yes | Yes |
| General | NullableToShorthand | Changes `Nullable<T>` to `T?`. | Yes | Yes |
| General | IfStatementWithoutBraces | Changes one-liner `if` and `else` statements to be surrounded in a block. | Yes | Yes |
| General | ConditionalOperatorReturnsDefaultOptions | The conditional operator shouldn't return redundant `true` and `false` literals. | Yes | Yes |
| General | CompareBooleanToTrueLiteral | A boolean expression doesn't have to be compared to true. | Yes | Yes |
| General | TypeToVar | Use `var` instead of an explicit type. | Yes | Yes |
| General | OnPropertyChangedWithoutNameOfOperator | Use the `nameof()` operator in conjunction with `OnPropertyChanged` | Yes | Yes |
| General | SimplifyExpressionBodiedMember | Simplify the expression using an expression-bodied member. | Yes | Yes |
| General | TryCastWithoutUsingAsNotNull | A conversion can be done using `as` + a `null` comparison. | Yes | Yes |
| General | NamingConventions | Implements the most common configuration of naming conventions. | Yes |Yes |
| General | NonEncapsulatedOrMutableField | A `public`, `internal` or `protected internal` non-`const`, non-`readonly` field should be used as a property. | Yes | Yes |
| Category | Name | Description
|:-:|:-:|:-:
| Async | VSD0001 | Asynchronous methods should end with -Async.
| Async | VSD0041 | A non-async, non-Task method should not end with -Async.
| Attributes | VSD0002 | Attributes with empty argument lists can have the argument list removed.
| Attributes | VSD0003 | Gives an enum the [Flags] attribute.
| Attributes | VSD0004 | A `[Flags]` enum its values are not explicit powers of 2
| Attributes | VSD0039 | A `[Flags]` enum its values are not explicit powers of 2 and does not fit in the specified enum type.
| Attributes | VSD0005 | Complains if the [Obsolete] attribute is used without an explicit reason.
| Attributes | VSD0006 | The `OnPropertyChanged()` method can automatically get the caller member name.
| Exceptions | VSD0007 | `ArgumentException` and its subclasses should use `nameof()` when they refer to a method parameter.
| Exceptions | VSD0008 | Guards against catching a NullReferenceException.
| Exceptions | VSD0009 | Guards against using an `ArgumentException` without specifying which argument.
| 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 | Guards against using a catch-all clause.
| General | VSD0013 | Allows you to change as statements to cast statements.
| General | VSD0014 | Allows you to change cast statements to as statements.
| General | VSD0015 | A boolean expression doesn't have to be compared to `false`.
| General | VSD0016 | A boolean expression doesn't have to be compared to `true`.
| General | VSD0017 | The conditional operator shouldn't return redundant `true` and `false` literals.
| General | VSD0018 | The conditional operator shouldn't return redundant `false` and `true` literals.
| General | VSD0019 | Complains about `if` statements of the form `if (statement) { /* body */ }`, where "statement" always evaluates to `false`.
| General | VSD0020 | Complains about `if` statements of the form `if (statement) { /* body */ }`, where "statement" always evaluates to `true`.
| General | VSD0021 | Inserts the default access modifier for a declaration.
| General | VSD0022 | Detects usage of the `goto` keyword.
| General | VSD0023 | Changes one-liner `if` and `else` statements to be surrounded in a block.
| General | VSD0024 | Loop blocks should use braces to denote start and end.
| General | VSD0025 | Implements the most common configuration of naming conventions.
| General | VSD0026 | A `public`, `internal` or `protected internal` non-`const`, non-`readonly` field should be used as a property.
| General | VSD0027 | Changes `Nullable<T>` to `T?`.
| General | VSD0028 | Use the `nameof()` operator in conjunction with `OnPropertyChanged`.
| General | VSD0029 | Simplify the expression using an expression-bodied member.
| General | VSD0030 | Warns about using a redundant default constructor.
| General | VSD0031 | A conversion can be done using `as` + a `null` comparison.
| General | VSD0032 | Use `var` instead of an explicit type.
| General | VSD0033 | Use the built-in type aliases instead of the concrete type.
| Strings | VSD0034 | Use `string.Empty` instead of `""`.
| Strings | VSD0035 | Adjusts the placeholders in `string.Format()` calls to be in numerical order.
| Strings | VSD0042 | A `string.Format()` call lacks arguments and will cause a runtime exception
| Structs | VSD0036 | Warns when a struct attempts to assign 'this' to a new instance of the struct.
| Tests | VSD0037 | Test methods do not need to use the "Test" suffic.
| Tests | VSD0038 | Change the access modifier to `public` for all methods annotated as test. Supports NUnit, MSTest and xUnit.net.

## How do I use this?

Expand All @@ -55,11 +77,33 @@ 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.

<img src="https://cloud.githubusercontent.com/assets/2777107/10696693/a1a2c82a-79a9-11e5-97bf-21f7e8c37356.PNG" />

## 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.

You'll need the [Visual Studio 2015 Release Candidate](https://www.visualstudio.com/en-us/downloads/visual-studio-2015-downloads-vs.aspx) and [the SDK](https://www.microsoft.com/en-us/download/details.aspx?id=46850) to get started.
You'll need [Visual Studio 2015](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx) and [the SDK](https://visualstudiogallery.msdn.microsoft.com/2ddb7240-5249-4c8c-969e-5d05823bcb89) to get started.

## 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](https://github.com/Vannevelj/VSDiagnostics/tree/develop/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/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](http://chat.stackexchange.com/rooms/26639/vsdiagnostics) where the main contributors reside.
2 changes: 1 addition & 1 deletion VSDiagnostics/VSDiagnostics.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.22823.1
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSDiagnostics", "VSDiagnostics\VSDiagnostics\VSDiagnostics.csproj", "{C7BF0415-8F01-4FF1-8EC3-71695197EF5B}"
EndProject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
namespace VSDiagnostics.Test.Tests.Async
{
[TestClass]
public class AsyncMethodWithoutAsyncSuffixAnalyzerTests : CSharpCodeFixVerifier
public class AsyncMethodWithoutAsyncSuffixTests : CSharpCodeFixVerifier
{
protected override CodeFixProvider CodeFixProvider => new AsyncMethodWithoutAsyncSuffixCodeFix();

protected override DiagnosticAnalyzer DiagnosticAnalyzer => new AsyncMethodWithoutAsyncSuffixAnalyzer();

[TestMethod]
public void AsyncMethodWithoutAsyncSuffixAnalyzer_WithAsyncKeywordAndNoSuffix_InvokesWarning()
public void AsyncMethodWithoutAsyncSuffix_WithAsyncMethodAndNoSuffix()
{
var original = @"
using System;
Expand All @@ -25,9 +25,9 @@ namespace ConsoleApplication1
{
class MyClass
{
async Task Method()
Task Method()
{
return Task.CompletedTask;
}
}
}";
Expand All @@ -41,9 +41,9 @@ namespace ConsoleApplication1
{
class MyClass
{
async Task MethodAsync()
Task MethodAsync()
{
return Task.CompletedTask;
}
}
}";
Expand All @@ -53,7 +53,7 @@ async Task MethodAsync()
}

[TestMethod]
public void AsyncMethodWithoutAsyncSuffixAnalyzer_WithAsyncKeywordAndSuffix_DoesNotDisplayWarning()
public void AsyncMethodWithoutAsyncSuffix_WithAsyncMethodAndSuffix()
{
var original = @"
using System;
Expand All @@ -64,17 +64,17 @@ namespace ConsoleApplication1
{
class MyClass
{
async Task MethodAsync()
Task MethodAsync()
{
return Task.CompletedTask;
}
}
}";
VerifyDiagnostic(original);
}

[TestMethod]
public void AsyncMethodWithoutAsyncSuffixAnalyzer_WithoutAsyncKeywordAndSuffix_DoesNotDisplayWarning()
public void AsyncMethodWithoutAsyncSuffix_WithSynchronousMethodAndNoSuffix()
{
var original = @"
using System;
Expand All @@ -87,11 +87,59 @@ class MyClass
{
void Method()
{
}
}
}";
VerifyDiagnostic(original);
}

[TestMethod]
public void AsyncMethodWithoutAsyncSuffix_WithInheritance()
{
var original = @"
using System;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
interface IMyInterface
{
Task MyMethod();
}
class MyClass : IMyInterface
{
public Task MyMethod()
{
return Task.CompletedTask;
}
}
}";

var result = @"
using System;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
interface IMyInterface
{
Task MyMethodAsync();
}
class MyClass : IMyInterface
{
public Task MyMethodAsync()
{
return Task.CompletedTask;
}
}
}";

VerifyDiagnostic(original, string.Format(AsyncMethodWithoutAsyncSuffixAnalyzer.Rule.MessageFormat.ToString(), "MyMethod"));
VerifyFix(original, result);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RoslynTester.Helpers.CSharp;
using VSDiagnostics.Diagnostics.Async.SyncMethodWithSyncSuffix;

namespace VSDiagnostics.Test.Tests.Async
{
[TestClass]
public class SyncMethodWithAsyncSuffixTests : CSharpCodeFixVerifier
{
protected override CodeFixProvider CodeFixProvider => new SyncMethodWithAsyncSuffixCodeFix();

protected override DiagnosticAnalyzer DiagnosticAnalyzer => new SyncMethodWithAsyncSuffixAnalyzer();

[TestMethod]
public void SyncMethodWithAsyncSuffix_WithSynchronousMethodAndNoSuffix()
{
var original = @"
using System;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class MyClass
{
void Method()
{
}
}
}";

VerifyDiagnostic(original);
}

[TestMethod]
public void SyncMethodWithAsyncSuffix_WithSynchronousMethodAndSuffix()
{
var original = @"
using System;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class MyClass
{
void MethodAsync()
{
}
}
}";

var result = @"
using System;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class MyClass
{
void Method()
{
}
}
}";

VerifyDiagnostic(original, string.Format(SyncMethodWithAsyncSuffixAnalyzer.Rule.MessageFormat.ToString(), "MethodAsync"));
VerifyFix(original, result);
}

[TestMethod]
public void SyncMethodWithAsyncSuffix_WithAsyncMethodAndSuffix()
{
var original = @"
using System;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class MyClass
{
async Task MethodAsync()
{
}
}
}";
VerifyDiagnostic(original);
}

[TestMethod]
public void SyncMethodWithAsyncSuffix_WithInheritance()
{
var original = @"
using System;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
interface IMyInterface
{
void MyMethodAsync();
}
class MyClass : IMyInterface
{
public void MyMethodAsync()
{
}
}
}";

var result = @"
using System;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
interface IMyInterface
{
void MyMethod();
}
class MyClass : IMyInterface
{
public void MyMethod()
{
}
}
}";

VerifyDiagnostic(original, string.Format(SyncMethodWithAsyncSuffixAnalyzer.Rule.MessageFormat.ToString(), "MyMethodAsync"));
VerifyFix(original, result);
}
}
}
Loading

0 comments on commit 888ec96

Please sign in to comment.