diff --git a/README.md b/README.md
index 3dfef54..1e2736f 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
-# 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.
+# VSDiagnostics
+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.
@@ -24,47 +25,68 @@ Currently these diagnostics are implemented:
| 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.
+| 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 | VSD0041 | A non-`async`, non-`Task` method should not end with -Async.
+| Async | VSD0064 | Async methods should return a `Task` to make them awaitable.
+| Attributes | VSD0002 | An attribute should not have an empty argument list.
+| 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.
+| Attributes | VSD0039 | A `[Flags]` enum its values are not explicit powers of 2 and its values dont fit in the specified enum type.
+| Attributes | VSD0005 | The `[Obsolete]` attribute doesn't have a reason.
+| Attributes | VSD0006 | `OnPropertyChanged()` can use the `[CallerMemberName]` attribute to automatically pass the property name.
+| Exceptions | VSD0007 | An `ArgumentException` should use `nameof()` to refer to a variable.
+| Exceptions | VSD0008 | Verifies no `NullReferenceException` is caught.
+| Exceptions | VSD0009 | Verifies whether an `ArgumentException` is thrown with a message.
| 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`.
+| Exceptions | VSD0012 | Verifies whether a try-catch block does not defer all exception handling to a single `Exception` clause.
+| 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 `Dispose` method.
+| Exceptions | VSD0058 | An exception is thrown from a finalizer method.
+| Exceptions | VSD0059 | An exception is thrown from a `GetHashCode()` method.
+| Exceptions | VSD0060 | An exception is thrown from an `Equals()` method.
+| Exceptions | VSD0065 | A `null` object is attempted to get thrown.
+| General | VSD0013 | Changes an `as` expression to a cast.
+| General | VSD0014 | Changes a cast expression to `as`.
+| General | VSD0015 | A boolean expression comparing to `false` can be simplified.
+| General | VSD0016 | A boolean expression comparing to `true` can be simplified.
+| 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 `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 | VSD0023 | Requires braces for `if`, `else`, `for`, `foreach`, `while`, `do`, `using`, `lock`, `fixed` and `switch` constructs.
| 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` 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.
+| General | VSD0030 | A constructor is the same as a default constructor and can be removed.
+| General | VSD0031 | Use `as`/`null` instead of `is`/`as`.
+| General | VSD0032 | Use `var` instead of the explicit type.
+| 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 `System.Random` is created in a loop.
+| General | VSD0046 | `Equals()` and `GetHashCode()` must be implemented together.
+| 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 | VSD0049 | A `switch` is missing a `default` label.\
+| General | VSD0052 | Implement `Equals()` and `GetHashCode()` using existing fields and properties.
+| General | VSD0063 | A `GetHashCode` implementation refers to a mutable field.
+| Strings | VSD0034 | Replaces an empty string literal with the more expressive `string.Empty`.
+| Strings | VSD0035 | Orders the arguments of a `string.Format()` call in ascending order according to index.
+| Strings | VSD0042 | A `string.Format()` call lacks arguments and will cause a runtime exception.
+| Structs | VSD0036 | Warns when a struct replaces `this` with a new instance.
+| Structs | VSD0050 | Structs should implement `Equals()`, `GetHashCode()`, and `ToString()`.
+| Tests | VSD0037 | A test method should not end with -Test.
+| Tests | VSD0038 | Verifies whether a test method has the `public` modifier.
+| Tests | VSD0062 | A method might be missing a test attribute.
## How do I use this?
@@ -72,7 +94,7 @@ Simply head over to [NuGet](https://www.nuget.org/packages/VSDiagnostics/) and i
## Can I request diagnostics?
-Yes, you can! Create an issue and we'll take a look at your proposal.
+Yes, you can! Create an issue and we'll take a look at your proposal.
## What if I don't like a diagnostic?
@@ -106,4 +128,4 @@ Release 2.0.0 will come with a website where we document every diagnostic includ
## 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.
+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 or send an email to jer_vannevel@outlook.com.
diff --git a/VSDiagnostics/VSDiagnostics.sln b/VSDiagnostics/VSDiagnostics.sln
index beec2dc..3e9980c 100644
--- a/VSDiagnostics/VSDiagnostics.sln
+++ b/VSDiagnostics/VSDiagnostics.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.24720.0
+# Visual Studio 15
+VisualStudioVersion = 15.0.27130.2027
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSDiagnostics", "VSDiagnostics\VSDiagnostics\VSDiagnostics.csproj", "{C7BF0415-8F01-4FF1-8EC3-71695197EF5B}"
EndProject
@@ -31,4 +31,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {43378104-E964-4E48-B654-B07D1FBFD96F}
+ EndGlobalSection
EndGlobal
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Arithmetic/DivideIntegerByIntegerTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Arithmetic/DivideIntegerByIntegerTests.cs
new file mode 100644
index 0000000..7c5930b
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Arithmetic/DivideIntegerByIntegerTests.cs
@@ -0,0 +1,425 @@
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.Arithmetic.DivideIntegerByInteger;
+
+namespace VSDiagnostics.Test.Tests.Arithmetic
+{
+ [TestClass]
+ public class DivideIntegerByIntegerTests : CSharpDiagnosticVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new DivideIntegerByIntegerAnalyzer();
+
+ [TestMethod]
+ public void DivideIntegerByInteger_TwoIntegers()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ int result = 5 / 6;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "5 / 6"));
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_IntegerAndDouble()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ double result = 5 / 6.0;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_DoubleAndInteger()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ double result = 5.0 / 6;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_DoubleAndDouble()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ double result = 5.0 / 6.0;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_ThreeIntegerOperands()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ double result = 5 / 6 / 2;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original,
+ string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "5 / 6 / 2"),
+ string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "5 / 6"));
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_ThreeIntegerOperands_TwoSubsequentIntegers_IntegerDivisionEvaluatedFirst()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ double result = 5 / 6 / 2.0;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "5 / 6"));
+ }
+
+ ///
+ /// This scenario is less important because 5.0 / 6 is evaluated first and results in a double.
+ /// In practice there will be no integer division here.
+ ///
+ [TestMethod]
+ public void DivideIntegerByInteger_ThreeIntegerOperands_TwoSubsequentIntegers_IntegerDivisionEvaluatedLast()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ double result = 5.0 / 6 / 2;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_ThreeIntegerOperands_NoSubsequentIntegerOperands()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ double result = 5 / 6.0 / 2;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_DynamicOperand()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ dynamic x = 5;
+ double result = x / 3;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_TwoIntegers_OneAsVariable()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ var x = 5;
+ double result = x / 3;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "x / 3"));
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_TwoIntegers_TwoAsVariables()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ var x = 5;
+ var y = 6;
+ double result = x / y;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "x / y"));
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_TwoIntegers_MethodReference()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ var y = 6;
+ double result = IntMethod() / y;
+ }
+
+ int IntMethod()
+ {
+ return 5;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "IntMethod() / y"));
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_TwoIntegers_InsideExpression()
+ {
+ var original = @"
+ using System;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ Console.WriteLine(5 / 6);
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "5 / 6"));
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_ShortAndShort()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ short x = 5;
+ short y = 6;
+ var result = x / y;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "x / y"));
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_LongAndLong()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ long x = 5;
+ long y = 6;
+ var result = x / y;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "x / y"));
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_LongAndInt()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ long x = 5;
+ int y = 6;
+ var result = x / y;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "x / y"));
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_ULongAndULong()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ ulong x = 5;
+ ulong y = 6;
+ var result = x / y;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "x / y"));
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_UIntAndUInt()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ uint x = 5;
+ uint y = 6;
+ var result = x / y;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "x / y"));
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_UShortAndUShort()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ ushort x = 5;
+ ushort y = 6;
+ var result = x / y;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "x / y"));
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_ByteAndByte()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ byte x = 5;
+ byte y = 6;
+ var result = x / y;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "x / y"));
+ }
+
+ [TestMethod]
+ public void DivideIntegerByInteger_SByteAndSByte()
+ {
+ var original = @"
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method()
+ {
+ sbyte x = 5;
+ sbyte y = 6;
+ var result = x / y;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(DivideIntegerByIntegerAnalyzer.Rule.MessageFormat.ToString(), "x / y"));
+ }
+ }
+}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Async/AsyncMethodWithVoidReturnTypeTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Async/AsyncMethodWithVoidReturnTypeTests.cs
new file mode 100644
index 0000000..b97d1c3
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Async/AsyncMethodWithVoidReturnTypeTests.cs
@@ -0,0 +1,262 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.Async.AsyncMethodWithVoidReturnType;
+
+namespace VSDiagnostics.Test.Tests.Async
+{
+ [TestClass]
+ public class AsyncMethodWithVoidReturnTypeTests : CSharpCodeFixVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new AsyncMethodWithVoidReturnTypeAnalyzer();
+ protected override CodeFixProvider CodeFixProvider => new AsyncMethodWithVoidReturnTypeCodeFix();
+
+ [TestMethod]
+ public void AsyncMethodWithVoidReturnType_WithAsyncAndTask()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ async Task MyMethod()
+ {
+ await Task.Run(() => { });
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void AsyncMethodWithVoidReturnType_NoAsync()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void MyMethod()
+ {
+
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void AsyncMethodWithVoidReturnType_WithAsyncAndTaskGeneric()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ async Task MyMethod()
+ {
+ return 32;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void AsyncMethodWithVoidReturnType_WithAsyncAndEventHandlerArguments()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ async void MyHandler(object o, EventArgs e)
+ {
+ await Task.Run(() => { });
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void AsyncMethodWithVoidReturnType_WithAsyncAndEventHandlerSubClassArguments()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ async void MyHandler(object o, MyEventArgs e)
+ {
+ await Task.Run(() => { });
+ }
+ }
+
+ class MyEventArgs : EventArgs
+ {
+
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void AsyncMethodWithVoidReturnType_WithAsyncDelegate()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ public void MyMethod()
+ {
+ TestMethod(async () => await Task.Run(() => {}));
+ }
+
+ public void TestMethod(Action callback)
+ {
+ callback();
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void AsyncMethodWithVoidReturnType_WithAsyncVoidAndArbitraryArguments()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ async void MyHandler(object o, int e)
+ {
+ await Task.Run(() => { });
+ }
+ }
+ }";
+
+ var result = @"
+ using System;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ async Task MyHandler(object o, int e)
+ {
+ await Task.Run(() => { });
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, "Method MyHandler is marked as async but has a void return type");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void AsyncMethodWithVoidReturnType_WithAsyncAndVoid()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ async void MyMethod()
+ {
+ await Task.Run(() => { });
+ }
+ }
+ }";
+
+ var result = @"
+ using System;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ async Task MyMethod()
+ {
+ await Task.Run(() => { });
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, "Method MyMethod is marked as async but has a void return type");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void AsyncMethodWithVoidReturnType_WithPartialMethod()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ namespace ConsoleApplication1
+ {
+ partial class A
+ {
+ partial void OnSomethingHappened();
+ }
+
+ partial class A
+ {
+ async partial void OnSomethingHappened()
+ {
+ await Task.Run(() => { });
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+ }
+}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Async/SyncMethodWithAsyncSuffixTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Async/SyncMethodWithAsyncSuffixTests.cs
index ab5248b..30871ff 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Async/SyncMethodWithAsyncSuffixTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Async/SyncMethodWithAsyncSuffixTests.cs
@@ -2,7 +2,7 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RoslynTester.Helpers.CSharp;
-using VSDiagnostics.Diagnostics.Async.SyncMethodWithSyncSuffix;
+using VSDiagnostics.Diagnostics.Async.SyncMethodWithAsyncSuffix;
namespace VSDiagnostics.Test.Tests.Async
{
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/AttributeWithEmptyArgumentListCSharpTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/AttributeWithEmptyArgumentListTests.cs
similarity index 89%
rename from VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/AttributeWithEmptyArgumentListCSharpTests.cs
rename to VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/AttributeWithEmptyArgumentListTests.cs
index c3b0a66..5f5720b 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/AttributeWithEmptyArgumentListCSharpTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/AttributeWithEmptyArgumentListTests.cs
@@ -7,7 +7,7 @@
namespace VSDiagnostics.Test.Tests.Attributes
{
[TestClass]
- public class AttributeWithEmptyArgumentListCSharpTests : CSharpCodeFixVerifier
+ public class AttributeWithEmptyArgumentListTests : CSharpCodeFixVerifier
{
protected override DiagnosticAnalyzer DiagnosticAnalyzer => new AttributeWithEmptyArgumentListAnalyzer();
@@ -44,7 +44,7 @@ void Method(string input)
}
}";
- VerifyDiagnostic(original, AttributeWithEmptyArgumentListAnalyzer.Rule.MessageFormat.ToString());
+ VerifyDiagnostic(original, string.Format(AttributeWithEmptyArgumentListAnalyzer.Rule.MessageFormat.ToString(), "Obsolete"));
VerifyFix(original, result);
}
@@ -122,7 +122,7 @@ enum Foo
}
}";
- VerifyDiagnostic(original, AttributeWithEmptyArgumentListAnalyzer.Rule.MessageFormat.ToString());
+ VerifyDiagnostic(original, string.Format(AttributeWithEmptyArgumentListAnalyzer.Rule.MessageFormat.ToString(), "Flags"));
VerifyFix(original, result);
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/AttributeWithEmptyArgumentListVisualBasicTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/AttributeWithEmptyArgumentListVisualBasicTests.cs
deleted file mode 100644
index eb85d81..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/AttributeWithEmptyArgumentListVisualBasicTests.cs
+++ /dev/null
@@ -1,137 +0,0 @@
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using RoslynTester.Helpers.VisualBasic;
-using VSDiagnostics.Diagnostics.Attributes.AttributeWithEmptyArgumentList;
-
-namespace VSDiagnostics.Test.Tests.Attributes
-{
- [TestClass]
- public class AttributeWithEmptyArgumentListVisualBasicTests : VisualBasicCodeFixVerifier
- {
- protected override DiagnosticAnalyzer DiagnosticAnalyzer => new AttributeWithEmptyArgumentListAnalyzer();
-
- protected override CodeFixProvider CodeFixProvider => new AttributeWithEmptyArgumentListCodeFix();
-
- [TestMethod]
- public void AttributeWithEmptyArgumentList_AttributeWithEmptyArgumentList()
- {
- var original = @"
-Imports System
-
-Module Module1
-
-
- Sub Foo()
-
- End Sub
-
-End Module";
-
- var result = @"
-Imports System
-
-Module Module1
-
-
- Sub Foo()
-
- End Sub
-
-End Module";
-
- VerifyDiagnostic(original, AttributeWithEmptyArgumentListAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void AttributeWithEmptyArgumentList_WithoutArgumentList()
- {
- var original = @"
-Imports System
-
-Module Module1
-
-
- Sub Foo()
-
- End Sub
-
-End Module";
-
- VerifyDiagnostic(original);
- }
-
- [TestMethod]
- public void AttributeWithEmptyArgumentList_WithArgumentList()
- {
- var original = @"
-Imports System
-
-Module Module1
-
-
- Sub Foo()
-
- End Sub
-
-End Module";
-
- VerifyDiagnostic(original);
- }
-
- // make sure it works on other attributes besides [Obsolete]
- [TestMethod]
- public void AttributeWithEmptyArgumentList_AttributeWithEmptyArgumentList_FlagsAttribute()
- {
- var original = @"
-Imports System
-
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- var result = @"
-Imports System
-
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(original, AttributeWithEmptyArgumentListAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- // make sure it works on other attributes besides [Obsolete]
- [TestMethod]
- public void AttributeWithEmptyArgumentList_WithoutArgumentList_FlagsAttribute()
- {
- var original = @"
-Imports System
-
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(original);
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/EnumCanHaveFlagsAttributeCSharpTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/EnumCanHaveFlagsAttributeTests.cs
similarity index 98%
rename from VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/EnumCanHaveFlagsAttributeCSharpTests.cs
rename to VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/EnumCanHaveFlagsAttributeTests.cs
index 0b41ab3..3d2cc06 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/EnumCanHaveFlagsAttributeCSharpTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/EnumCanHaveFlagsAttributeTests.cs
@@ -7,7 +7,7 @@
namespace VSDiagnostics.Test.Tests.Attributes
{
[TestClass]
- public class EnumCanHaveFlagsAttributeCSharpTests : CSharpCodeFixVerifier
+ public class EnumCanHaveFlagsAttributeTests : CSharpCodeFixVerifier
{
protected override DiagnosticAnalyzer DiagnosticAnalyzer => new EnumCanHaveFlagsAttributeAnalyzer();
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/EnumCanHaveFlagsAttributeVisualBasicTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/EnumCanHaveFlagsAttributeVisualBasicTests.cs
deleted file mode 100644
index 3094c25..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/EnumCanHaveFlagsAttributeVisualBasicTests.cs
+++ /dev/null
@@ -1,165 +0,0 @@
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using RoslynTester.Helpers.VisualBasic;
-using VSDiagnostics.Diagnostics.Attributes.EnumCanHaveFlagsAttribute;
-
-namespace VSDiagnostics.Test.Tests.Attributes
-{
- [TestClass]
- public class EnumCanHaveFlagsAttributeVisualBasicTests : VisualBasicCodeFixVerifier
- {
- protected override DiagnosticAnalyzer DiagnosticAnalyzer => new EnumCanHaveFlagsAttributeAnalyzer();
-
- protected override CodeFixProvider CodeFixProvider => new EnumCanHaveFlagsAttributeCodeFix();
-
- [TestMethod]
- public void EnumCanHaveFlagsAttribute_AddsFlagsAttribute()
- {
- var original = @"
-Module Module1
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- var result = @"
-Imports System
-Module Module1
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(original, EnumCanHaveFlagsAttributeAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void EnumCanHaveFlagsAttribute_AddsFlagsAttribute_OnlyAddsFlagsAttribute()
- {
- var original = @"
-Imports System
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- var result = @"
-Imports System
-Module Module1
-
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(original, EnumCanHaveFlagsAttributeAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void EnumCanHaveFlagsAttribute_EnumHasXmlDocComment_OnlyAddsFlagsAttribute()
- {
- var original = @"
-Module Module1
-
- '''
- ''' Doc comment for Foo...
- '''
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- var result = @"
-Imports System
-Module Module1
-
- '''
- ''' Doc comment for Foo...
- '''
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(original, EnumCanHaveFlagsAttributeAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void EnumCanHaveFlagsAttribute_InspectionDoesNotReturnWhenFlagsAlreadyApplied()
- {
- var original = @"
-Imports System
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(original);
- }
-
- [TestMethod]
- public void EnumCanHaveFlagsAttribute_InspectionDoesNotReturnWhenFlagsAttributeAlreadyApplied()
- {
- var original = @"
-Imports System
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(original);
- }
-
- [TestMethod]
- public void EnumCanHaveFlagsAttribute_InspectionDoesNotReturnWhenFlagsAlreadyAppliedAsChain()
- {
- var original = @"
-Imports System
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(original);
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/ObsoleteAttributeWithoutReasonCSharpTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/ObsoleteAttributeWithoutReasonTests.cs
similarity index 97%
rename from VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/ObsoleteAttributeWithoutReasonCSharpTests.cs
rename to VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/ObsoleteAttributeWithoutReasonTests.cs
index 5266f07..7447827 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/ObsoleteAttributeWithoutReasonCSharpTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/ObsoleteAttributeWithoutReasonTests.cs
@@ -6,7 +6,7 @@
namespace VSDiagnostics.Test.Tests.Attributes
{
[TestClass]
- public class ObsoleteAttributeWithoutReasonCSharpTests : CSharpDiagnosticVerifier
+ public class ObsoleteAttributeWithoutReasonTests : CSharpDiagnosticVerifier
{
protected override DiagnosticAnalyzer DiagnosticAnalyzer => new ObsoleteAttributeWithoutReasonAnalyzer();
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/ObsoleteAttributeWithoutReasonVisualBasicTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/ObsoleteAttributeWithoutReasonVisualBasicTests.cs
deleted file mode 100644
index 655b86b..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/ObsoleteAttributeWithoutReasonVisualBasicTests.cs
+++ /dev/null
@@ -1,175 +0,0 @@
-using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using RoslynTester.Helpers.VisualBasic;
-using VSDiagnostics.Diagnostics.Attributes.ObsoleteAttributeWithoutReason;
-
-namespace VSDiagnostics.Test.Tests.Attributes
-{
- [TestClass]
- public class ObsoleteAttributeWithoutReasonVisualBasicTests : VisualBasicDiagnosticVerifier
- {
- protected override DiagnosticAnalyzer DiagnosticAnalyzer => new ObsoleteAttributeWithoutReasonAnalyzer();
-
- [TestMethod]
- public void ObsoleteAttributeWithoutReason_WithObsoleteWithNullArgumentList()
- {
- var test = @"
-Imports System
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(test, ObsoleteAttributeWithoutReasonAnalyzer.Rule.MessageFormat.ToString());
- }
-
- [TestMethod]
- public void ObsoleteAttributeWithoutReason_WithObsoleteAttributeWithoutReason()
- {
- var test = @"
-Imports System
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(test, ObsoleteAttributeWithoutReasonAnalyzer.Rule.MessageFormat.ToString());
- }
-
- [TestMethod]
- public void ObsoleteAttributeWithoutReason_WithObsoleteWithEmptyArgumentList()
- {
- var test = @"
-Imports System
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(test, ObsoleteAttributeWithoutReasonAnalyzer.Rule.MessageFormat.ToString());
- }
-
- [TestMethod]
- public void ObsoleteAttributeWithoutReason_WithObsoleteAttributeWithEmptyArgumentList()
- {
- var test = @"
-Imports System
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(test, ObsoleteAttributeWithoutReasonAnalyzer.Rule.MessageFormat.ToString());
- }
-
- [TestMethod]
- public void ObsoleteAttributeWithoutReason_WithObsoleteWithArgument()
- {
- var test = @"
-Imports System
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(test);
- }
-
- [TestMethod]
- public void ObsoleteAttributeWithoutReason_WithObsoleteAttributeWithArgument()
- {
- var test = @"
-Imports System
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(test);
- }
-
- [TestMethod]
- public void ObsoleteAttributeWithoutReason_WithObsoleteWithArguments()
- {
- var test = @"
-Imports System
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(test);
- }
-
- [TestMethod]
- public void ObsoleteAttributeWithoutReason_WithObsoleteAttributeWithArguments()
- {
- var test = @"
-Imports System
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(test);
- }
-
- [TestMethod]
- public void ObsoleteAttributeWithoutReason_NonObsoleteAttribute()
- {
- var test = @"
-Imports System
-Module Module1
-
-
- Enum Foo
- Bar
- Baz
- End Enum
-
-End Module";
-
- VerifyDiagnostic(test);
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/OnPropertyChangedWithoutCallerMemberNameTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/OnPropertyChangedWithoutCallerMemberNameTests.cs
index f7c1cd7..85d6d56 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/OnPropertyChangedWithoutCallerMemberNameTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Attributes/OnPropertyChangedWithoutCallerMemberNameTests.cs
@@ -454,5 +454,43 @@ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName
VerifyDiagnostic(original, OnPropertyChangedWithoutCallerMemberNameAnalyzer.Rule.MessageFormat.ToString());
VerifyFix(original, result);
}
+
+ [TestMethod]
+ public void OnPropertyChangedWithoutCallerMemberName_StructImplementsINotifyPropertyChanged()
+ {
+ var original = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ struct Foo : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+ public void OnPropertyChanged(string propertyName)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Runtime.CompilerServices;
+
+namespace ConsoleApplication1
+{
+ struct Foo : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+ public void OnPropertyChanged([CallerMemberName] string propertyName = """")
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, OnPropertyChangedWithoutCallerMemberNameAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/ArgumentExceptionWithoutNameofOperatorTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/ArgumentExceptionWithoutNameofOperatorTests.cs
index 464c70b..ff37d74 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/ArgumentExceptionWithoutNameofOperatorTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/ArgumentExceptionWithoutNameofOperatorTests.cs
@@ -434,5 +434,127 @@ public MyException(string message) : base(message)
VerifyDiagnostic(original, string.Format(ArgumentExceptionWithoutNameofOperatorAnalyzer.Rule.MessageFormat.ToString(), "input"));
VerifyFix(original, result);
}
+
+ [TestMethod]
+ public void ArgumentExceptionWithoutNameofOperator_PropertySetter()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ public int MyProperty
+ {
+ get { return 5; }
+ set { throw new ArgumentException(""value""); }
+ }
+ }
+ }";
+
+ var result = @"
+ using System;
+ using System.Text;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ public int MyProperty
+ {
+ get { return 5; }
+ set { throw new ArgumentException(nameof(value)); }
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, string.Format(ArgumentExceptionWithoutNameofOperatorAnalyzer.Rule.MessageFormat.ToString(), "value"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ArgumentExceptionWithoutNameofOperator_PropertySetter_UsesNameofValue()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ public int MyProperty
+ {
+ get { return 5; }
+ set { throw new ArgumentException(nameof(value)); }
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ArgumentExceptionWithoutNameofOperator_PropertyGetterOnly()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ public int MyProperty
+ {
+ get { return 5; }
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ArgumentExceptionWithoutNameofOperator_PropertyExpressionBodied()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ public int MyProperty => 5;
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ArgumentExceptionWithoutNameofOperator_PropertySetterDoesNotReferToValue()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ public int MyProperty
+ {
+ get { return 5; }
+ set { throw new ArgumentNullException(""test""); }
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/ExceptionThrownFromProhibitedContextTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/ExceptionThrownFromProhibitedContextTests.cs
new file mode 100644
index 0000000..ef2a0cd
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/ExceptionThrownFromProhibitedContextTests.cs
@@ -0,0 +1,701 @@
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.Exceptions.ExceptionThrownFromProhibitedContext;
+
+namespace VSDiagnostics.Test.Tests.Exceptions
+{
+ [TestClass]
+ public class ExceptionThrownFromProhibitedContextTests : CSharpDiagnosticVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new ExceptionThrownFromProhibitedContextAnalyzer();
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_ImplicitOperator_ToType()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public static implicit operator MyClass(double d)
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from implicit operator MyClass in type MyClass");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_ImplicitOperator_FromType()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public static implicit operator double(MyClass d)
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from implicit operator double in type MyClass");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_ImplicitOperator_ExplicitOperator()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public static explicit operator double(MyClass d)
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_PropertyGetter()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public int MyProp
+ {
+ get
+ {
+ throw new ArgumentException();
+ }
+ set
+ {
+
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from the getter of property MyProp");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_PropertyGetter_Setter()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public int MyProp
+ {
+ get
+ {
+ return 5;
+ }
+ set
+ {
+ throw new ArgumentException();
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_PropertyGetter_AutoProperty()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public int MyProp { get; set; }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_PropertyGetter_ExpressionBodiedProperty()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public int MyProp => 5;
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_PropertyGetter_NoSetter()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public int MyProp
+ {
+ get
+ {
+ throw new ArgumentException();
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from the getter of property MyProp");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_StaticConstructor_Class()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ static MyClass()
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from MyClass its static constructor");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_StaticConstructor_Struct()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyStruct
+ {
+ static MyStruct()
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from MyStruct its static constructor");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_StaticConstructor_InstanceConstructor()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ MyClass()
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_FinallyBlock()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ void MyMethod()
+ {
+ try { } finally { throw new ArgumentException(); }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from a finally block");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_FinallyBlock_NoException()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ void MyMethod()
+ {
+ try { } finally { }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_FinallyBlock_NoFinally()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ void MyMethod()
+ {
+ try { } catch { }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_EqualityOperator_EqualOperator()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public static bool operator ==(double d, MyClass mc)
+ {
+ throw new ArgumentException();
+ }
+
+ public static bool operator !=(double d, MyClass mc)
+ {
+ return false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from the == operator between double and MyClass in type MyClass");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_EqualityOperator_NotEqualOperator()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public static bool operator ==(double d, MyClass mc)
+ {
+ return false;
+ }
+
+ public static bool operator !=(double d, MyClass mc)
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from the != operator between double and MyClass in type MyClass");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_EqualityOperator_NoThrow()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public static bool operator ==(double d, MyClass mc)
+ {
+ return false;
+ }
+
+ public static bool operator !=(double d, MyClass mc)
+ {
+ return false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_Dispose()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass : IDisposable
+ {
+ public void Dispose()
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from the Dispose() method in type MyClass");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_Dispose_BoolArgument()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass : IDisposable
+ {
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ public void Dispose(bool dispose)
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from the Dispose(bool) method in type MyClass");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_Dispose_NoIDisposable()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public void Dispose()
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from the Dispose() method in type MyClass");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_Dispose_DifferentMethod()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass : IDisposable
+ {
+ public void OtherName()
+ {
+ throw new ArgumentException();
+ }
+
+ public void Dispose()
+ {
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_Finalize()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ ~MyClass()
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from the finalizer method in type MyClass");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_Finalize_NoThrow()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ ~MyClass()
+ {
+
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_GetHashCode()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public override int GetHashCode()
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from the GetHashCode() method in type MyClass");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_GetHashCode_NoThrow()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public override int GetHashCode()
+ {
+ return 5;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_GetHashCode_HidingMember()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public int GetHashCode()
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_Equals()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public override bool Equals(object o)
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from the Equals(object) method in type MyClass");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_Equals_IEquatable()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass : IEquatable
+ {
+ public bool Equals(MyClass o)
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from the Equals(MyClass) method in type MyClass");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_Equals_NoThrow()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public override bool Equals(object o)
+ {
+ return false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_Equals_HidingMember()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ public class MyClass
+ {
+ public bool Equals(object o)
+ {
+ throw new ArgumentException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An exception is thrown from the Equals(object) method in type MyClass");
+ }
+
+ [TestMethod]
+ public void ExceptionThrownFromProhibitedContext_Indexer()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public string this[int i]
+ {
+ get
+ {
+ throw new ArgumentException();
+ }
+
+ set { }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/SingleGeneralExceptionTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/SingleGeneralExceptionTests.cs
index e21cc71..47b5df4 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/SingleGeneralExceptionTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/SingleGeneralExceptionTests.cs
@@ -10,7 +10,11 @@ public class SingleGeneralExceptionTests : CSharpDiagnosticVerifier
{
protected override DiagnosticAnalyzer DiagnosticAnalyzer => new SingleGeneralExceptionAnalyzer();
+ ///
+ /// Ignored until https://github.com/Vannevelj/RoslynTester/issues/32
+ ///
[TestMethod]
+ [Ignore]
public void SingleGeneralException_WithSingleGeneralException()
{
var test = @"
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/ThrowNullTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/ThrowNullTests.cs
new file mode 100644
index 0000000..07a59f0
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Exceptions/ThrowNullTests.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.Exceptions.ThrowNull;
+
+namespace VSDiagnostics.Test.Tests.Exceptions
+{
+ [TestClass]
+ public class ThrowNullTests : CSharpDiagnosticVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new ThrowNullAnalyzer();
+
+ [TestMethod]
+ public void ThrowNull_ThrowsNull()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method(string input)
+ {
+ throw null;
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original, "Throwing null will always result in a runtime exception");
+ }
+
+ [TestMethod]
+ public void ThrowNull_DoesNotThrowNull()
+ {
+ var original = @"
+ using System;
+ using System.Text;
+
+ namespace ConsoleApplication1
+ {
+ class MyClass
+ {
+ void Method(string input)
+ {
+ throw new Exception();
+ }
+ }
+ }";
+
+ VerifyDiagnostic(original);
+ }
+ }
+}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/AsToCastTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/AsToCastTests.cs
index dddc345..c26c940 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/AsToCastTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/AsToCastTests.cs
@@ -14,7 +14,7 @@ public class AsToCastTests : CSharpCodeFixVerifier
protected override CodeFixProvider CodeFixProvider => new AsToCastCodeFix();
[TestMethod]
- public void AsToCast_PredefinedType()
+ public void AsToCast_NullableValueType()
{
var original = @"
namespace ConsoleApplication1
@@ -190,5 +190,50 @@ void Method()
VerifyDiagnostic(original, AsToCastAnalyzer.Rule.MessageFormat.ToString());
VerifyFix(original, result);
}
+
+ [TestMethod]
+ public void AsToCast_Generics()
+ {
+ var original = @"
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ static class Extensions
+ {
+ public static void Method(this IEnumerable input) where T : class
+ {
+ var list = new List();
+
+ foreach (var node in input)
+ {
+ list.Add(node as T);
+ }
+ }
+ }
+}";
+
+ var result = @"
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ static class Extensions
+ {
+ public static void Method(this IEnumerable input) where T : class
+ {
+ var list = new List();
+
+ foreach (var node in input)
+ {
+ list.Add((T)node);
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, AsToCastAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/CastToAsTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/CastToAsTests.cs
index bf6a979..327fb64 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/CastToAsTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/CastToAsTests.cs
@@ -23,12 +23,11 @@ class MyClass
{
void Method()
{
- var ch = 'r';
- var i = (int) ch;
+ char ch = 'r';
+ int i = (int) ch;
}
}
}";
-
VerifyDiagnostic(original);
}
@@ -197,5 +196,74 @@ void Main()
VerifyDiagnostic(original, CastToAsAnalyzer.Rule.MessageFormat.ToString());
VerifyFix(original, result);
}
+
+ [TestMethod]
+ public void CastToAs_Generics()
+ {
+ var original = @"
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ static class Extensions
+ {
+ public static void Method(this IEnumerable input) where T : class
+ {
+ var list = new List();
+
+ foreach (var node in input)
+ {
+ list.Add((T)node);
+ }
+ }
+ }
+}";
+
+ var result = @"
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ static class Extensions
+ {
+ public static void Method(this IEnumerable input) where T : class
+ {
+ var list = new List();
+
+ foreach (var node in input)
+ {
+ list.Add(node as T);
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, CastToAsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void CastToAs_Generics_ValueType()
+ {
+ var original = @"
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ static class Extensions
+ {
+ public static void Method(this IEnumerable input) where T : struct
+ {
+ var list = new List();
+
+ foreach (var node in input)
+ {
+ list.Add((T)node);
+ }
+ }
+ }
+}";
+ VerifyDiagnostic(original);
+ }
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/CompareBooleanToFalseLiteralTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/CompareBooleanToFalseLiteralTests.cs
index 59e783a..92bfeb3 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/CompareBooleanToFalseLiteralTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/CompareBooleanToFalseLiteralTests.cs
@@ -966,5 +966,44 @@ void Method()
VerifyDiagnostic(original, CompareBooleanToFalseLiteralAnalyzer.Rule.MessageFormat.ToString());
VerifyFix(original, result);
}
+
+ [TestMethod]
+ public void CompareBooleanToFalseLiteral_DoesNotReformatEntireDocment()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method () // formatting removes space before parens
+ {
+ bool isAwesome = false;
+ if(isAwesome == false) // formatting adds space before parens
+ {
+ System.Console.WriteLine(""awesome"");
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method () // formatting removes space before parens
+ {
+ bool isAwesome = false;
+ if(!isAwesome) // formatting adds space before parens
+ {
+ System.Console.WriteLine(""awesome"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, CompareBooleanToFalseLiteralAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/CompareBooleanToTrueLiteralTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/CompareBooleanToTrueLiteralTests.cs
index f743225..4233269 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/CompareBooleanToTrueLiteralTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/CompareBooleanToTrueLiteralTests.cs
@@ -1055,5 +1055,50 @@ void Method()
VerifyDiagnostic(original, CompareBooleanToTrueLiteralAnalyzer.Rule.MessageFormat.ToString());
VerifyFix(original, result);
}
+
+ [TestMethod]
+ public void CompareBooleanToTrueLiteral_DoesNotReformatEntireDoc()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method () // formatting removes space before parens
+ {
+ bool isAwesome = true;
+ if(isAwesome == true) // formatting adds space before parens
+ {
+ Console.WriteLine(""awesome"");
+ }
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method () // formatting removes space before parens
+ {
+ bool isAwesome = true;
+ if(isAwesome) // formatting adds space before parens
+ {
+ Console.WriteLine(""awesome"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, CompareBooleanToTrueLiteralAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionIsAlwaysFalseTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionIsAlwaysFalseTests.cs
deleted file mode 100644
index f1dc790..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionIsAlwaysFalseTests.cs
+++ /dev/null
@@ -1,379 +0,0 @@
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using RoslynTester.Helpers.CSharp;
-using VSDiagnostics.Diagnostics.General.ConditionIsAlwaysFalse;
-
-namespace VSDiagnostics.Test.Tests.General
-{
- [TestClass]
- public class ConditionIsAlwaysFalseTests : CSharpCodeFixVerifier
- {
- protected override DiagnosticAnalyzer DiagnosticAnalyzer => new ConditionIsAlwaysFalseAnalyzer();
-
- protected override CodeFixProvider CodeFixProvider => new ConditionIsAlwaysFalseCodeFix();
-
- [TestMethod]
- public void ConditionIsAlwaysFalse_ConditionHasBraces()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if (false)
- {
- var b = true;
- b = false;
- }
- }
- }
-}";
-
- var result = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysFalseAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysFalse_ConditionDoesNotHaveBraces()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
-
- if (false)
- b = false;
-
- if (b) { } // prevent variable is never used warning for fix
- }
- }
-}";
-
- var result = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
-
- if (b) { } // prevent variable is never used warning for fix
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysFalseAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysFalse_ConditionContainsTrueLiteral()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
-
- if (b && false)
- b = false;
- }
- }
-}";
-
- VerifyDiagnostic(original);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysFalse_WithElse_ConditionHasBraces()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if (false)
- {
- var b = true;
- b = false;
- }
- else
- {
- var b = true;
-
- if (b) { } // prevent variable is never used warning for fix
- }
- }
- }
-}";
-
- var result = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
-
- if (b) { } // prevent variable is never used warning for fix
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysFalseAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysFalse_WithElse_ConditionDoesNotHaveBraces()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
-
- if (false)
- b = false;
- else
- b = false;
-
- if (b) { } // prevent variable is never used warning for fix
- }
- }
-}";
-
- var result = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
- b = false;
-
- if (b) { } // prevent variable is never used warning for fix
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysFalseAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysFalse_WithElseIf_ConditionHasBraces()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if (false)
- {
- var b = true;
- b = false;
- }
- else if (9 == 8)
- {
- var b = true;
- b = false;
- }
- }
- }
-}";
-
- var result = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if (9 == 8)
- {
- var b = true;
- b = false;
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysFalseAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysFalse_WithElseIf_ConditionDoesNotHaveBraces()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
-
- if (false)
- b = false;
- else if (9 == 8)
- b = false;
-
- if (b) { } // prevent variable is never used warning for fix
- }
- }
-}";
-
- var result = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
- if (9 == 8)
- b = false;
-
- if (b) { } // prevent variable is never used warning for fix
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysFalseAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysFalse_WithElseIfElse_ConditionHasBraces()
- {
- var original = @"
-using System;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if (false)
- {
- var b = true;
- b = false;
- }
- else if (9 == 8)
- {
- Console.WriteLine("""");
- }
- else
- {
- Console.WriteLine("""");
- }
- }
- }
-}";
-
- var result = @"
-using System;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if (9 == 8)
- {
- Console.WriteLine("""");
- }
- else
- {
- Console.WriteLine("""");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysFalseAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysFalse_WithElseIfElse_ConditionDoesNotHaveBraces()
- {
- var original = @"
-using System;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
-
- if (false)
- b = false;
- else if (9 == 8)
- b = false;
- else
- Console.WriteLine("""");
- }
- }
-}";
-
- var result = @"
-using System;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
- if (9 == 8)
- b = false;
- else
- Console.WriteLine("""");
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysFalseAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionIsAlwaysTrueTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionIsAlwaysTrueTests.cs
deleted file mode 100644
index 3c4e3dd..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionIsAlwaysTrueTests.cs
+++ /dev/null
@@ -1,362 +0,0 @@
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using RoslynTester.Helpers.CSharp;
-using VSDiagnostics.Diagnostics.General.ConditionIsAlwaysTrue;
-
-namespace VSDiagnostics.Test.Tests.General
-{
- [TestClass]
- public class ConditionIsAlwaysTrueTests : CSharpCodeFixVerifier
- {
- protected override DiagnosticAnalyzer DiagnosticAnalyzer => new ConditionIsAlwaysTrueAnalyzer();
-
- protected override CodeFixProvider CodeFixProvider => new ConditionIsAlwaysTrueCodeFix();
-
- [TestMethod]
- public void ConditionIsAlwaysTrue_ConditionHasBraces()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if (true)
- {
- var b = true;
- b = false;
- }
- }
- }
-}";
-
- var result = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
- b = false;
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysTrueAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysTrue_ConditionDoesNotHaveBraces()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
-
- if (true)
- b = false;
- }
- }
-}";
-
- var result = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
- b = false;
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysTrueAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysTrue_ConditionContainsTrueLiteral()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
-
- if (b && true)
- b = false;
- }
- }
-}";
-
- VerifyDiagnostic(original);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysTrue_WithElse_ConditionHasBraces()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if (true)
- {
- var b = true;
- b = false;
- }
- else
- {
- var b = true;
-
- if (b) { } // prevent variable is never used warning for fix
- }
- }
- }
-}";
-
- var result = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
- b = false;
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysTrueAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysTrue_WithElse_ConditionDoesNotHaveBraces()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
-
- if (true)
- b = false;
- else
- b = false;
-
- if (b) { } // prevent variable is never used warning for fix
- }
- }
-}";
-
- var result = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
- b = false;
-
- if (b) { } // prevent variable is never used warning for fix
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysTrueAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysTrue_WithElseIf_ConditionHasBraces()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if (true)
- {
- var b = true;
- b = false;
- }
- else if (9 == 8)
- {
- var b = true;
- b = false;
- }
- }
- }
-}";
-
- var result = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
- b = false;
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysTrueAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysTrue_WithElseIf_ConditionDoesNotHaveBraces()
- {
- var original = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
-
- if (true)
- b = false;
- else if (9 == 8)
- b = false;
-
- if (b) { } // prevent variable is never used warning for fix
- }
- }
-}";
-
- var result = @"
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
- b = false;
-
- if (b) { } // prevent variable is never used warning for fix
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysTrueAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysTrue_WithElseIfElse_ConditionHasBraces()
- {
- var original = @"
-using System;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if (true)
- {
- Console.WriteLine("""");
- }
- else if (9 == 8)
- {
- Console.WriteLine("""");
- }
- else
- {
- Console.WriteLine("""");
- }
- }
- }
-}";
-
- var result = @"
-using System;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- Console.WriteLine("""");
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysTrueAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void ConditionIsAlwaysTrue_WithElseIfElse_ConditionDoesNotHaveBraces()
- {
- var original = @"
-using System;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
-
- if (true)
- Console.WriteLine("""");
- else if (9 == 8)
- b = false;
- else
- Console.WriteLine("""");
- }
- }
-}";
-
- var result = @"
-using System;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var b = true;
- Console.WriteLine("""");
- }
- }
-}";
-
- VerifyDiagnostic(original, ConditionIsAlwaysTrueAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionIsConstantTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionIsConstantTests.cs
new file mode 100644
index 0000000..5a6c2e3
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionIsConstantTests.cs
@@ -0,0 +1,1261 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.General.ConditionIsConstant;
+
+namespace VSDiagnostics.Test.Tests.General
+{
+ [TestClass]
+ public class ConditionIsConstantTests : CSharpCodeFixVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new ConditionIsConstantAnalyzer();
+
+ protected override CodeFixProvider CodeFixProvider => new ConditionIsConstantCodeFix();
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_ConditionHasBraces()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if (true)
+ {
+ var b = true;
+ b = false;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+ b = false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_ConditionDoesNotHaveBraces()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+
+ if (true)
+ b = false;
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+ b = false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_ConditionContainsTrueLiteral()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+
+ if (b && true)
+ b = false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_WithElse_ConditionHasBraces()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if (true)
+ {
+ var b = true;
+ b = false;
+ }
+ else
+ {
+ var b = true;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+ b = false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_WithElse_ConditionDoesNotHaveBraces()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+
+ if (true)
+ b = false;
+ else
+ b = false;
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+ b = false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_WithElseIf_ConditionHasBraces()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var variable = true;
+ if (true)
+ {
+ var b = true;
+ b = false;
+ }
+ else if (variable)
+ {
+ var b = true;
+ b = false;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var variable = true;
+ var b = true;
+ b = false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_WithElseIf_ChildIfIsAlwaysTrue_IfIsInBlockNode()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var potentiallyTrue = true;
+ if (potentiallyTrue)
+ {
+ var b = true;
+ b = false;
+ }
+ else
+ {
+ if (true)
+ {
+ var b = true;
+ b = false;
+ }
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var potentiallyTrue = true;
+ if (potentiallyTrue)
+ {
+ var b = true;
+ b = false;
+ }
+ else
+ {
+ var b = true;
+ b = false;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_WithElseIf_ChildIfIsAlwaysTrue_IfIsInElseNode()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var potentiallyTrue = true;
+ if (potentiallyTrue)
+ {
+ var b = true;
+ b = false;
+ }
+ else if (true)
+ {
+ var b = true;
+ b = false;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var potentiallyTrue = true;
+ if (potentiallyTrue)
+ {
+ var b = true;
+ b = false;
+ }
+ else
+ {
+ var b = true;
+ b = false;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_WithElseIf_ConditionDoesNotHaveBraces()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+
+ if (true)
+ b = false;
+ else if (b)
+ b = false;
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+ b = false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_WithElseIfElse_ConditionHasBraces()
+ {
+ var original = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var v = true;
+ if (true)
+ {
+ Console.WriteLine("""");
+ }
+ else if (v)
+ {
+ Console.WriteLine("""");
+ }
+ else
+ {
+ Console.WriteLine("""");
+ }
+ }
+ }
+}";
+
+ var result = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var v = true;
+ Console.WriteLine("""");
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_WithElseIfElse_ConditionDoesNotHaveBraces()
+ {
+ var original = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+
+ if (true)
+ Console.WriteLine("""");
+ else if (b)
+ b = false;
+ else
+ Console.WriteLine("""");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+ Console.WriteLine("""");
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_ConstantBooleanComparedToBooleanLiteralTrue()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const bool lit = true;
+ if (lit == true)
+ {
+ var dummyVal = 0;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const bool lit = true;
+ var dummyVal = 0;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_ConstantBooleanComparedToBooleanLiteralFalse()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const bool lit = false;
+ if (lit == false)
+ {
+ var dummyVal = 0;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const bool lit = false;
+ var dummyVal = 0;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_ConstantBoolean()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const bool lit = true;
+ if (lit)
+ {
+ var dummyVal = 0;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const bool lit = true;
+ var dummyVal = 0;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_ConstantInteger()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const int lit = 5;
+ if (lit == 5)
+ {
+ var dummyVal = 0;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const int lit = 5;
+ var dummyVal = 0;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysTrue_CompareIdenticalLiterals()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if (5 == 5)
+ {
+ var dummyVal = 0;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var dummyVal = 0;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "true"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_ConditionHasBraces()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if (false)
+ {
+ var b = true;
+ b = false;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_ConditionDoesNotHaveBraces()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+
+ if (false)
+ b = false;
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_ConditionContainsTrueLiteral()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+
+ if (b && false)
+ b = false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_WithElse_ConditionHasBraces()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if (false)
+ {
+ var b = true;
+ b = false;
+ }
+ else
+ {
+ var b = true;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_WithElse_ConditionDoesNotHaveBraces()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+
+ if (false)
+ b = false;
+ else
+ b = false;
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+ b = false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_WithElseIf_ConditionHasBraces()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var v = true;
+ if (false)
+ {
+ var b = true;
+ b = false;
+ }
+ else if (v)
+ {
+ var b = true;
+ b = false;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var v = true;
+ if (v)
+ {
+ var b = true;
+ b = false;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_WithElseIf_ConditionDoesNotHaveBraces()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+
+ if (false)
+ b = false;
+ else if (b)
+ b = false;
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+ if (b)
+ b = false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_WithElseIfElse_ConditionHasBraces()
+ {
+ var original = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var v = true;
+ if (false)
+ {
+ var b = true;
+ b = false;
+ }
+ else if (v)
+ {
+ Console.WriteLine("""");
+ }
+ else
+ {
+ Console.WriteLine("""");
+ }
+ }
+ }
+}";
+
+ var result = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var v = true;
+ if (v)
+ {
+ Console.WriteLine("""");
+ }
+ else
+ {
+ Console.WriteLine("""");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_WithElseIfElse_ConditionDoesNotHaveBraces()
+ {
+ var original = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+
+ if (false)
+ b = false;
+ else if (b)
+ b = false;
+ else
+ Console.WriteLine("""");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var b = true;
+ if (b)
+ b = false;
+ else
+ Console.WriteLine("""");
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_ConstantBooleanComparedToBooleanLiteralTrue()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const bool lit = false;
+ if (lit == true)
+ {
+ var dummyVal = 0;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const bool lit = false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_ConstantBooleanComparedToBooleanLiteralFalse()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const bool lit = true;
+ if (lit == false)
+ {
+ var dummyVal = 0;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const bool lit = true;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_ConstantBoolean()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const bool lit = false;
+ if (lit)
+ {
+ var dummyVal = 0;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const bool lit = false;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_ConstantInteger()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const int lit = 5;
+ if (lit == 4)
+ {
+ var dummyVal = 0;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ const int lit = 5;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_CompareNonidenticalLiterals()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if (5 == 4)
+ {
+ var dummyVal = 0;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS0219");
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_WithElseIf_ChildIfIsAlwaysFalse_IfIsInBlockNode()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var potentiallyTrue = true;
+ if (potentiallyTrue)
+ {
+ var b = true;
+ b = false;
+ }
+ else
+ {
+ if (false)
+ {
+ var b = true;
+ b = false;
+ }
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var potentiallyTrue = true;
+ if (potentiallyTrue)
+ {
+ var b = true;
+ b = false;
+ }
+ else
+ {
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ConditionIsAlwaysFalse_WithElseIf_ChildIfIsAlwaysFalse_IfIsInElseNode()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var potentiallyTrue = true;
+ if (potentiallyTrue)
+ {
+ var b = true;
+ b = false;
+ }
+ else if (false)
+ {
+ var b = true;
+ b = false;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var potentiallyTrue = true;
+ if (potentiallyTrue)
+ {
+ var b = true;
+ b = false;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(ConditionIsConstantAnalyzer.Rule.MessageFormat.ToString(), "false"));
+ VerifyFix(original, result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionalOperatorReturnsDefaultOptionsTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionalOperatorReturnsDefaultOptionsTests.cs
index 38c4013..53e1fb9 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionalOperatorReturnsDefaultOptionsTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionalOperatorReturnsDefaultOptionsTests.cs
@@ -252,5 +252,46 @@ void Method()
VerifyDiagnostic(original);
}
+
+ [TestMethod]
+ public void ConditionalOperatorReturnsDefaultOptions_DoesNotReformatEntireDocument()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method () // formatter removes space before parens
+ {
+ int legalAge = 18;
+ int myAge = 22;
+ bool canDrink = myAge >= legalAge ? true : false;
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method () // formatter removes space before parens
+ {
+ int legalAge = 18;
+ int myAge = 22;
+ bool canDrink = myAge >= legalAge;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, ConditionalOperatorReturnsDefaultOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionalOperatorReturnsInvertedDefaultOptionsTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionalOperatorReturnsInvertedDefaultOptionsTests.cs
index f84e4b4..6d24f16 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionalOperatorReturnsInvertedDefaultOptionsTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ConditionalOperatorReturnsInvertedDefaultOptionsTests.cs
@@ -252,5 +252,40 @@ void Method()
VerifyDiagnostic(original);
}
+
+ [TestMethod]
+ public void ConditionalOperatorReturnsInvertedDefaultOptions_DoesNotReformatEntireDocument()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method () // formatter removes space before parens
+ {
+ int legalAge = 18;
+ int myAge = 22;
+ bool canDrink = myAge >= legalAge ? false : true;
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method () // formatter removes space before parens
+ {
+ int legalAge = 18;
+ int myAge = 22;
+ bool canDrink = !(myAge >= legalAge);
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, ConditionalOperatorReturnsInvertedDefaultOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ElementaryMethodsOfTypeInCollectionNotOverriddenTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ElementaryMethodsOfTypeInCollectionNotOverriddenTests.cs
new file mode 100644
index 0000000..b32cef9
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ElementaryMethodsOfTypeInCollectionNotOverriddenTests.cs
@@ -0,0 +1,354 @@
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.General.ElementaryMethodsOfTypeInCollectionNotOverridden;
+
+namespace VSDiagnostics.Test.Tests.General
+{
+ [TestClass]
+ public class ElementaryMethodsOfTypeInCollectionNotOverriddenTests : CSharpDiagnosticVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer();
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_WithReferenceType()
+ {
+ var original = @"
+using System.Collections.Generic;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ }
+ }
+
+ class MyCollectionItem {}
+}";
+
+ VerifyDiagnostic(original, ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer.Rule.MessageFormat.ToString());
+ }
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_WithInterfaceType()
+ {
+ var original = @"
+using System.Collections.Generic;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ }
+ }
+
+ interface MyCollectionItem {}
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_WithValueType()
+ {
+ var original = @"
+using System.Collections.Generic;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ }
+ }
+
+ struct MyCollectionItem {}
+}";
+
+ VerifyDiagnostic(original, ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer.Rule.MessageFormat.ToString());
+ }
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_WithReferenceType_ImplementsEquals()
+ {
+ var original = @"
+using System.Collections.Generic;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ }
+ }
+
+ class MyCollectionItem
+ {
+ public override bool Equals(object obj)
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer.Rule.MessageFormat.ToString());
+ }
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_WithValueType_ImplementsEquals()
+ {
+ var original = @"
+using System.Collections.Generic;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ }
+ }
+
+ struct MyCollectionItem
+ {
+ public override bool Equals(object obj)
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer.Rule.MessageFormat.ToString());
+ }
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_WithReferenceType_ImplementsGetHashCode()
+ {
+ var original = @"
+using System.Collections.Generic;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ }
+ }
+
+ class MyCollectionItem
+ {
+ public override int GetHashCode()
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer.Rule.MessageFormat.ToString());
+ }
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_WithValueType_ImplementsGetHashCode()
+ {
+ var original = @"
+using System.Collections.Generic;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ }
+ }
+
+ struct MyCollectionItem
+ {
+ public override int GetHashCode()
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer.Rule.MessageFormat.ToString());
+ }
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_WithReferenceType_ImplementsMethods()
+ {
+ var original = @"
+using System.Collections.Generic;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ }
+ }
+
+ class MyCollectionItem
+ {
+ public override bool Equals(object obj)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override int GetHashCode()
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_WithValueType_ImplementsMethods()
+ {
+ var original = @"
+using System.Collections.Generic;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ }
+ }
+
+ struct MyCollectionItem
+ {
+ public override bool Equals(object obj)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override int GetHashCode()
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_Dictionary_BothDoNotImplementMethods()
+ {
+ var original = @"
+using System.Collections.Generic;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new Dictionary();
+ }
+ }
+
+ class MyCollectionItem {}
+}";
+
+ VerifyDiagnostic(original,
+ ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer.Rule.MessageFormat.ToString(),
+ ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer.Rule.MessageFormat.ToString());
+ }
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_Dictionary_OneDoesNotImplementMethods()
+ {
+ var original = @"
+using System.Collections.Generic;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new Dictionary();
+ }
+ }
+
+ class MyCollectionItem {}
+}";
+
+ VerifyDiagnostic(original,
+ ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer.Rule.MessageFormat.ToString());
+ }
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_TypeParameterWithoutObjectCreation()
+ {
+ var original = @"
+using System.Linq;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = Enumerable.Empty();
+ }
+ }
+
+ class MyCollectionItem {}
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_GenericTypeFromClass()
+ {
+ var original = @"
+using System.Collections.Generic;
+namespace ConsoleApplication1
+{
+ internal class MyClass
+ {
+ public static List Method()
+ {
+ var newList = new List();
+ return newList;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ElementaryMethodsOfTypeInCollectionNotOverridden_GenericTypeFromMethod()
+ {
+ var original = @"
+using System.Collections.Generic;
+namespace ConsoleApplication1
+{
+ internal class MyClass
+ {
+ public static List Method()
+ {
+ var newList = new List();
+ return newList;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/EqualsAndGetHashcodeNotImplementedTogetherTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/EqualsAndGetHashcodeNotImplementedTogetherTests.cs
new file mode 100644
index 0000000..55fc134
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/EqualsAndGetHashcodeNotImplementedTogetherTests.cs
@@ -0,0 +1,300 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.General.EqualsAndGetHashcodeNotImplementedTogether;
+
+namespace VSDiagnostics.Test.Tests.General
+{
+ [TestClass]
+ public class EqualsAndGetHashcodeNotImplementedTogetherTests : CSharpCodeFixVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new EqualsAndGetHashcodeNotImplementedTogetherAnalyzer();
+ protected override CodeFixProvider CodeFixProvider => new EqualsAndGetHashcodeNotImplementedTogetherCodeFix();
+
+ [TestMethod]
+ public void EqualsAndGetHashcodeNotImplemented_BothImplemented_NoWarning()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public override bool Equals(object obj)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override int GetHashCode()
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void EqualsAndGetHashcodeNotImplemented_EqualsImplemented()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public override bool Equals(object obj)
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public override bool Equals(object obj)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override int GetHashCode()
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, EqualsAndGetHashcodeNotImplementedTogetherAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void EqualsAndGetHashcodeNotImplemented_GetHashcodeImplemented()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public override int GetHashCode()
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public override int GetHashCode()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override bool Equals(object obj)
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, EqualsAndGetHashcodeNotImplementedTogetherAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void EqualsAndGetHashcodeNotImplemented_NeitherImplemented_NoWarning()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void EqualsAndGetHashcodeNotImplemented_NonOverridingEqualsImplemented_NoWarning()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public bool Equals(object obj)
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void EqualsAndGetHashcodeNotImplemented_NonOverridingGetHashcodeImplemented_NoWarning()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int GetHashCode()
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void EqualsAndGetHashcodeNotImplemented_EqualsImplemented_SimplifiesNameWhenUsingSystem()
+ {
+ var original = @"
+using System;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public override bool Equals(object obj)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ var result = @"
+using System;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public override bool Equals(object obj)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override int GetHashCode()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, EqualsAndGetHashcodeNotImplementedTogetherAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void EqualsAndGetHashcodeNotImplemented_GetHashcodeImplemented_SimplifiesNameWhenUsingSystem()
+ {
+ var original = @"
+using System;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public override int GetHashCode()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ var result = @"
+using System;
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public override int GetHashCode()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override bool Equals(object obj)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, EqualsAndGetHashcodeNotImplementedTogetherAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void EqualsAndGetHashcodeNotImplemented_GetHashcodeImplemented_BaseClassImplementsBoth()
+ {
+ var original = @"
+using System;
+namespace ConsoleApplication1
+{
+ class MyBaseClass
+ {
+ public override int GetHashCode()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override bool Equals(object obj)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ class MyClass : MyBaseClass
+ {
+ public override int GetHashCode()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ var result = @"
+using System;
+namespace ConsoleApplication1
+{
+ class MyBaseClass
+ {
+ public override int GetHashCode()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override bool Equals(object obj)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ class MyClass : MyBaseClass
+ {
+ public override int GetHashCode()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override bool Equals(object obj)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, EqualsAndGetHashcodeNotImplementedTogetherAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/GetHashCodeRefersToMutableFieldTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/GetHashCodeRefersToMutableFieldTests.cs
new file mode 100644
index 0000000..de383a6
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/GetHashCodeRefersToMutableFieldTests.cs
@@ -0,0 +1,361 @@
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.General.GetHashCodeRefersToMutableMember;
+
+namespace VSDiagnostics.Test.Tests.General
+{
+ [TestClass]
+ public class GetHashCodeRefersToMutableMemberTests : CSharpDiagnosticVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new GetHashCodeRefersToMutableMemberAnalyzer();
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_ConstantField()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ private const char Boo = '1';
+
+ public override int GetHashCode()
+ {
+ return Boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "GetHashCode() refers to const field Boo");
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_NonReadonlyField()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ private char _boo = '1';
+
+ public override int GetHashCode()
+ {
+ return _boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "GetHashCode() refers to non-readonly field _boo");
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_StaticField()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ private static readonly char _boo = '1';
+
+ public override int GetHashCode()
+ {
+ return _boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "GetHashCode() refers to static field _boo");
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_NonReadonlyStaticNonValueTypeField()
+ {
+ var original = @"
+using System;
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ private static Type _boo = typeof(Foo);
+
+ public override int GetHashCode()
+ {
+ return _boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "GetHashCode() refers to static non-readonly non-value type, non-string field _boo");
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_NonValueTypeNonStringField()
+ {
+ var original = @"
+using System;
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ private readonly Type _boo = typeof(Foo);
+
+ public override int GetHashCode()
+ {
+ return _boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "GetHashCode() refers to non-value type, non-string field _boo");
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_ImmutableMember_NoWarning()
+ {
+ var original = @"
+using System;
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ private readonly char _boo = '1';
+
+ public override int GetHashCode()
+ {
+ return _boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_ImmutableStringMember_NoWarning()
+ {
+ var original = @"
+using System;
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ private readonly string _boo = ""1"";
+
+ public override int GetHashCode()
+ {
+ return _boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_StaticProperty()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ public static char Boo { get; } = '1';
+
+ public override int GetHashCode()
+ {
+ return Boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "GetHashCode() refers to static property Boo");
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_NonValueTypeNonStringProperty()
+ {
+ var original = @"
+using System;
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ public Type Boo { get; } = typeof(Foo);
+
+ public override int GetHashCode()
+ {
+ return Boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "GetHashCode() refers to non-value type, non-string property Boo");
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_SettableProperty()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ public char Boo { get; set; } = '1';
+
+ public override int GetHashCode()
+ {
+ return Boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "GetHashCode() refers to settable property Boo");
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_PropertyWithBodiedGetter()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ public char Boo { get { return '1'; } }
+
+ public override int GetHashCode()
+ {
+ return Boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "GetHashCode() refers to property with bodied getter Boo");
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_StaticNonValueTypeSettablePropertyWithBodiedGetter()
+ {
+ var original = @"
+using System;
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ public static Type Boo { get { return typeof(Foo); } set { } }
+
+ public override int GetHashCode()
+ {
+ return Boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "GetHashCode() refers to static non-value type, non-string settable property with bodied getter Boo");
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_PropertyWithExpressionBodiedGetter()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ public char Boo => '1';
+
+ public override int GetHashCode()
+ {
+ return Boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "GetHashCode() refers to property with bodied getter Boo");
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_ImmutableProperty_NoDiagnostic()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ public char Boo { get; }
+
+ public override int GetHashCode()
+ {
+ return Boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_ImmutableStringProperty_NoDiagnostic()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ public class Foo
+ {
+ public string Boo { get; }
+
+ public override int GetHashCode()
+ {
+ return Boo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_InOtherType_PropertyWithExpressionBodiedGetter()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ public struct Bar
+ {
+ public int Fuzz => 0;
+ }
+
+ public class Foo
+ {
+ private readonly Bar _bar = new Bar();
+ public override int GetHashCode() => _bar.Fuzz.GetHashCode();
+ }
+}";
+
+ VerifyDiagnostic(original, "GetHashCode() refers to property with bodied getter Fuzz");
+ }
+
+ [TestMethod]
+ public void GetHashCodeRefersToMutableMember_InOtherType_ImmutableProperty_NoDiagnostic()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ public struct Bar
+ {
+ public int Fizz { get; }
+ }
+
+ public class Foo
+ {
+ private readonly Bar _bar = new Bar();
+ public override int GetHashCode() => _bar.Fizz.GetHashCode();
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+ }
+}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/IfStatementWithoutBracesTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/IfStatementWithoutBracesTests.cs
deleted file mode 100644
index 44d9abd..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/IfStatementWithoutBracesTests.cs
+++ /dev/null
@@ -1,413 +0,0 @@
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using RoslynTester.Helpers.CSharp;
-using VSDiagnostics.Diagnostics.General.IfStatementWithoutBraces;
-
-namespace VSDiagnostics.Test.Tests.General
-{
- [TestClass]
- public class IfStatementWithoutBracesTests : CSharpCodeFixVerifier
- {
- protected override DiagnosticAnalyzer DiagnosticAnalyzer => new IfStatementWithoutBracesAnalyzer();
-
- protected override CodeFixProvider CodeFixProvider => new IfStatementWithoutBracesCodeFix();
-
- [TestMethod]
- public void IfStatementWithoutBraces_WithoutBraces_OnSameLine()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true) Console.WriteLine(""true"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, IfStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void IfStatementWithoutBraces_WithoutBraces_OnSameLine_WithIntermittentComment()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true) /* comments */ Console.WriteLine(""true"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true) /* comments */
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, IfStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void IfStatementWithoutBraces_WithoutBraces_OnNextLine()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true)
- Console.WriteLine(""true"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, IfStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void IfStatementWithoutBraces_WithBraces()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
- VerifyDiagnostic(original);
- }
-
- [TestMethod]
- public void IfStatementWithoutBraces_ElseStatementWithoutBraces_OnSameLine()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true)
- {
- Console.WriteLine(""true"");
- }
- else Console.WriteLine(""false"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true)
- {
- Console.WriteLine(""true"");
- }
- else
- {
- Console.WriteLine(""false"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, IfStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void IfStatementWithoutBraces_ElseStatementWithoutBraces_OnNextLine()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true)
- {
- Console.WriteLine(""true"");
- }
- else
- Console.WriteLine(""false"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true)
- {
- Console.WriteLine(""true"");
- }
- else
- {
- Console.WriteLine(""false"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, IfStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void IfStatementWithoutBraces_ElseStatementWithBraces()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true)
- {
- Console.WriteLine(""true"");
- }
- else
- {
- Console.WriteLine(""false"");
- }
- }
- }
-}";
- VerifyDiagnostic(original);
- }
-
- [TestMethod]
- public void IfStatementWithoutBraces_IfAndElseWithoutBraces()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true)
- Console.WriteLine(""true"");
- else
- Console.WriteLine(""false"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- if(true)
- {
- Console.WriteLine(""true"");
- }
- else
- {
- Console.WriteLine(""false"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original,
- IfStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString(),
- IfStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void IfStatementWithoutBraces_ElseIfWithBraces()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var i = 5;
- if (i == 5)
- {
- Console.WriteLine(""true"");
- }
- else if (i == 4)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original);
- }
-
- [TestMethod]
- public void IfStatementWithoutBraces_ElseIfWithoutBraces()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var i = 5;
- if (i == 5)
- {
- Console.WriteLine(""true"");
- }
- else if (i == 4)
- Console.WriteLine(""true"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var i = 5;
- if (i == 5)
- {
- Console.WriteLine(""true"");
- }
- else if (i == 4)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, IfStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ImplementEqualsAndGetHashCodeTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ImplementEqualsAndGetHashCodeTests.cs
new file mode 100644
index 0000000..8b11dc6
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/ImplementEqualsAndGetHashCodeTests.cs
@@ -0,0 +1,1560 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.General.ImplementEqualsAndGetHashCode;
+
+namespace VSDiagnostics.Test.Tests.General
+{
+ [TestClass]
+ public class ImplementEqualsAndGetHashCodeTests : CSharpCodeFixVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new ImplementEqualsAndGetHashCodeAnalyzer();
+ protected override CodeFixProvider CodeFixProvider => new ImplementEqualsAndGetHashCodeCodeFix();
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_HasReadonlyField()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"";
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"";
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo == value._foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_HasGetOnlyProperty()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ string Foo { get; } = ""test"";
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ string Foo { get; } = ""test"";
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return Foo == value.Foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return Foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_HasMultipleFieldsAndProperties()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"";
+ readonly string _bar = ""test"";
+
+ string Foo { get; } = ""test"";
+ string Bar { get; } = ""test"";
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"";
+ readonly string _bar = ""test"";
+
+ string Foo { get; } = ""test"";
+ string Bar { get; } = ""test"";
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo == value._foo &&
+ _bar == value._bar &&
+ Foo == value.Foo &&
+ Bar == value.Bar;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode() ^
+ _bar.GetHashCode() ^
+ Foo.GetHashCode() ^
+ Bar.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_HasSetOnlyProperty()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"";
+ string _bar = ""test"";
+
+ string Foo { get; } = ""test"";
+ string Bar
+ {
+ set { _bar = value; }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"";
+ string _bar = ""test"";
+
+ string Foo { get; } = ""test"";
+ string Bar
+ {
+ set { _bar = value; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo == value._foo &&
+ _bar == value._bar &&
+ Foo == value.Foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode() ^
+ Foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_DoesNotHaveFieldOrProperty()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassImplementsEquals_HasField()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ string _foo = ""test"";
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo == value._foo;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_StructDoesNotImplementEither_HasField()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ readonly string _foo;
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ readonly string _foo;
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyStruct) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyStruct)obj;
+ return _foo == value._foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Struct MyStruct does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_StructDoesNotImplementEither_HasProperty()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ string Foo { get; }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ string Foo { get; }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyStruct) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyStruct)obj;
+ return Foo == value.Foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return Foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Struct MyStruct does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_StructDoesNotImplementEither_HasMultipleFieldsAndProperties()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ readonly string _foo;
+ readonly string _bar;
+
+ string Foo { get; }
+ string Bar { get; }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ readonly string _foo;
+ readonly string _bar;
+
+ string Foo { get; }
+ string Bar { get; }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyStruct) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyStruct)obj;
+ return _foo == value._foo &&
+ _bar == value._bar &&
+ Foo == value.Foo &&
+ Bar == value.Bar;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode() ^
+ _bar.GetHashCode() ^
+ Foo.GetHashCode() ^
+ Bar.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Struct MyStruct does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_StructDoesNotImplementEither_HasSetOnlyProperty()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ readonly string _foo;
+ string _bar;
+
+ string Foo { get; }
+ string Bar
+ {
+ set { _bar = value; }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ readonly string _foo;
+ string _bar;
+
+ string Foo { get; }
+ string Bar
+ {
+ set { _bar = value; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyStruct) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyStruct)obj;
+ return _foo == value._foo &&
+ _bar == value._bar &&
+ Foo == value.Foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode() ^
+ Foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Struct MyStruct does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_StructDoesNotImplementEither_DoesNotHaveFieldOrProperty()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_StructImplementsEquals_HasField()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ string _foo;
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyStruct) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyStruct)obj;
+ return _foo == value._foo;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_HasChainedFields()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"", _bar = ""test"";
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"", _bar = ""test"";
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo == value._foo &&
+ _bar == value._bar;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode() ^
+ _bar.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_HasStaticFields()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"";
+ static string _bar = ""test"";
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"";
+ static string _bar = ""test"";
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo == value._foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_HasConstFields()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"";
+ const string _bar = ""test"";
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"";
+ const string _bar = ""test"";
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo == value._foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_HasBaseClassImplementingEquals()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyBaseClass
+ {
+ public override bool Equals(object obj) => true;
+ }
+
+ class MyClass : MyBaseClass
+ {
+ readonly string _foo = ""test"";
+ static string _bar = ""test"";
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyBaseClass
+ {
+ public override bool Equals(object obj) => true;
+ }
+
+ class MyClass : MyBaseClass
+ {
+ readonly string _foo = ""test"";
+ static string _bar = ""test"";
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return base.Equals(obj) &&
+ _foo == value._foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_HasBaseClassImplementingEquals_HasInterface()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ interface IClass { }
+
+ class MyBaseClass
+ {
+ public override bool Equals(object obj) => true;
+ }
+
+ class MyClass : MyBaseClass, IClass
+ {
+ readonly string _foo = ""test"";
+ static string _bar = ""test"";
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ interface IClass { }
+
+ class MyBaseClass
+ {
+ public override bool Equals(object obj) => true;
+ }
+
+ class MyClass : MyBaseClass, IClass
+ {
+ readonly string _foo = ""test"";
+ static string _bar = ""test"";
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return base.Equals(obj) &&
+ _foo == value._foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_StructDoesNotImplementEither_ImplementsInterface()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ interface IStruct { }
+
+ struct MyStruct : IStruct
+ {
+ readonly string _foo;
+ static string _bar;
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ interface IStruct { }
+
+ struct MyStruct : IStruct
+ {
+ readonly string _foo;
+ static string _bar;
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyStruct) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyStruct)obj;
+ return _foo == value._foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Struct MyStruct does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_HasBaseClassImplementingEquals_BaseClassHasField()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyBaseClass
+ {
+ public string foo;
+ public override bool Equals(object obj) => true;
+ }
+
+ class MyClass : MyBaseClass
+ {
+ readonly string _foo = ""test"";
+ static string _bar = ""test"";
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyBaseClass
+ {
+ public string foo;
+ public override bool Equals(object obj) => true;
+ }
+
+ class MyClass : MyBaseClass
+ {
+ readonly string _foo = ""test"";
+ static string _bar = ""test"";
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return base.Equals(obj) &&
+ _foo == value._foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_HasBaseBaseClassImplementingEquals_BaseBaseClassHasField()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class A
+ {
+ public virtual bool M { get { return true; } }
+ public override bool Equals(object obj) => true;
+ }
+
+ class B : A { }
+
+ class C : B
+ {
+ public override bool M { get { return true; } }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class A
+ {
+ public virtual bool M { get { return true; } }
+ public override bool Equals(object obj) => true;
+ }
+
+ class B : A { }
+
+ class C : B
+ {
+ public override bool M { get { return true; } }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(C) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (C)obj;
+ return base.Equals(obj) &&
+ M.Equals(value.M);
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return base.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class C does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_HasBaseClassNotImplementingEquals()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyBaseClass
+ {
+ public string foo;
+ public override int GetHashCode() => 1; // disable analyzer for this
+ }
+
+ class MyClass : MyBaseClass
+ {
+ readonly string _foo = ""test"";
+ static string _bar = ""test"";
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyBaseClass
+ {
+ public string foo;
+ public override int GetHashCode() => 1; // disable analyzer for this
+ }
+
+ class MyClass : MyBaseClass
+ {
+ readonly string _foo = ""test"";
+ static string _bar = ""test"";
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo == value._foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesImplementsEquals_OverridesPropertyInBaseClass()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyBaseClass
+ {
+ public virtual string Bar { get; }
+ public override bool Equals(object obj) => true;
+ }
+
+ class MyClass : MyBaseClass
+ {
+ readonly string _foo = ""test"";
+ static string _bar = ""test"";
+ public override string Bar { get; }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyBaseClass
+ {
+ public virtual string Bar { get; }
+ public override bool Equals(object obj) => true;
+ }
+
+ class MyClass : MyBaseClass
+ {
+ readonly string _foo = ""test"";
+ static string _bar = ""test"";
+ public override string Bar { get; }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return base.Equals(obj) &&
+ _foo == value._foo &&
+ Bar == value.Bar;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode() ^
+ Bar.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_EqualsComparesAll_GetHashCodeUsesReadonly()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"";
+ string _bar = ""test"";
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo = ""test"";
+ string _bar = ""test"";
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo == value._foo &&
+ _bar == value._bar;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_EqualsComparesAll_GetHashCodeUsesValueTypes()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct { }
+ class MyClassN { }
+
+ class MyClass
+ {
+ readonly int _foo = 0;
+ readonly MyStruct _bar;
+ readonly MyClassN _fizz;
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct { }
+ class MyClassN { }
+
+ class MyClass
+ {
+ readonly int _foo = 0;
+ readonly MyStruct _bar;
+ readonly MyClassN _fizz;
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo.Equals(value._foo) &&
+ _bar.Equals(value._bar) &&
+ _fizz == value._fizz;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode() ^
+ _bar.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_EqualsComparesAll_GetHashCodeUsesString()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo;
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ readonly string _foo;
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo == value._foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_EqualsComparesAll_GetHashCodeDoesNotUseInterface()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ interface IClass { }
+
+ class MyClass
+ {
+ readonly string _foo;
+ readonly IClass _bar;
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ interface IClass { }
+
+ class MyClass
+ {
+ readonly string _foo;
+ readonly IClass _bar;
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo == value._foo &&
+ _bar == value._bar;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_EqualsComparesAll_GetHashCodeReturnsBaseGetHashCodeWhenNoEligbleValues()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ interface IClass { }
+
+ class MyClass
+ {
+ readonly IClass _bar;
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ interface IClass { }
+
+ class MyClass
+ {
+ readonly IClass _bar;
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _bar == value._bar;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return base.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_EqualsComparesAll_GetHashCodeUsesBodylessGetOnlyProperties()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ string _foo { get; set; }
+ string _bar { get; }
+ string _fizz { get { return ""test""; } }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ string _foo { get; set; }
+ string _bar { get; }
+ string _fizz { get { return ""test""; } }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo == value._foo &&
+ _bar == value._bar &&
+ _fizz == value._fizz;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _bar.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_NeitherUsesDelegates()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ string _foo { get; }
+ public delegate int PerformCalculation(int x, int y);
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ string _foo { get; }
+ public delegate int PerformCalculation(int x, int y);
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo == value._foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_EqualsUsesEqualsOnValueTypes()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct { }
+
+ class MyClass
+ {
+ readonly MyStruct _foo;
+ MyStruct _bar { get; }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct { }
+
+ class MyClass
+ {
+ readonly MyStruct _foo;
+ MyStruct _bar { get; }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo.Equals(value._foo) &&
+ _bar.Equals(value._bar);
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return _foo.GetHashCode() ^
+ _bar.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_ClassDoesNotImplementEither_HasExpressionBodiedProperty()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ string Foo => ""test"";
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ string Foo => ""test"";
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return Foo == value.Foo;
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return base.GetHashCode();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_PartialClassDoesNotImplementEither_ImplementsAllTypesInSplitClass()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ public partial class MyClass
+ {
+ private int _foo;
+ }
+
+ public partial class MyClass
+ {
+ private int _bar;
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ public partial class MyClass
+ {
+ private int _foo;
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _foo.Equals(value._foo) &&
+ _bar.Equals(value._bar);
+ }
+
+ public override int GetHashCode()
+ {
+ // Add any fields you're interested in, taking into account the guidelines described in
+ // https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+ return base.GetHashCode();
+ }
+ }
+
+ public partial class MyClass
+ {
+ private int _bar;
+ }
+}";
+
+ // two diagnostics because it is reported in two places
+ VerifyDiagnostic(original, "Class MyClass does not implement Equals() and GetHashCode().",
+ "Class MyClass does not implement Equals() and GetHashCode().");
+ VerifyFix(original, result, 0);
+ }
+
+ [TestMethod]
+ public void ImplementEqualsAndGetHashCode_PartialClassImplementsEquals()
+ {
+ var firstTree = @"
+namespace ConsoleApplication1
+{
+ public partial class MyClass
+ {
+ private int _foo;
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null || typeof(MyClass) != obj.GetType())
+ {
+ return false;
+ }
+
+ var value = (MyClass)obj;
+ return _bar.Equals(value._bar) &&
+ _foo.Equals(value._foo);
+ }
+ }
+}";
+
+ var secondTree = @"
+namespace ConsoleApplication1
+{
+ public partial class MyClass
+ {
+ private int _bar;
+ }
+}";
+
+ VerifyDiagnostic(new[] {firstTree, secondTree});
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/LoopStatementWithoutBracesTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/LoopStatementWithoutBracesTests.cs
deleted file mode 100644
index 3730a98..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/LoopStatementWithoutBracesTests.cs
+++ /dev/null
@@ -1,612 +0,0 @@
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using RoslynTester.Helpers.CSharp;
-using VSDiagnostics.Diagnostics.General.LoopStatementWithoutBraces;
-
-namespace VSDiagnostics.Test.Tests.General
-{
- [TestClass]
- public class LoopStatementWithoutBracesTests : CSharpCodeFixVerifier
- {
- protected override DiagnosticAnalyzer DiagnosticAnalyzer => new LoopStatementWithoutBracesAnalyzer();
-
- protected override CodeFixProvider CodeFixProvider => new LoopStatementWithoutBracesCodeFix();
-
- [TestMethod]
- public void LoopStatementWithoutBraces_For_WithoutBraces_OnSameLine()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- for (int i = 0; i < 10; i++) Console.WriteLine(""true"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- for (int i = 0; i < 10; i++)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, LoopStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_For_WithoutBraces_OnSameLine_WithIntermittentComment()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- for (int i = 0; i < 10; i++) /* comments */ Console.WriteLine(""true"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- for (int i = 0; i < 10; i++) /* comments */
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, LoopStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_For_WithoutBraces_OnNextLine()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- for (int i = 0; i < 10; i++)
- Console.WriteLine(""true"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- for (int i = 0; i < 10; i++)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, LoopStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_For_WithBraces()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- for (int i = 0; i < 10; i++)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
- VerifyDiagnostic(original);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_While_WithoutBraces_OnSameLine()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- while (true) Console.WriteLine(""true"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- while (true)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, LoopStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_While_WithoutBraces_OnSameLine_WithIntermittentComment()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- while (true) /* comments */ Console.WriteLine(""true"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- while (true) /* comments */
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, LoopStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_While_WithoutBraces_OnNextLine()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- while (true)
- Console.WriteLine(""true"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- while (true)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, LoopStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_While_WithBraces()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- while (true)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
- VerifyDiagnostic(original);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_Foreach_WithoutBraces_OnSameLine()
- {
- var original = @"
-using System;
-using System.Text;
-using System.Collections.Generic;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var list = new List();
- foreach (var item in list) Console.WriteLine(""true"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-using System.Collections.Generic;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var list = new List();
- foreach (var item in list)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, LoopStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_Foreach_WithoutBraces_OnSameLine_WithIntermittentComment()
- {
- var original = @"
-using System;
-using System.Text;
-using System.Collections.Generic;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var list = new List();
- foreach (var item in list) /* comments */ Console.WriteLine(""true"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-using System.Collections.Generic;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var list = new List();
- foreach (var item in list) /* comments */
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, LoopStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_Foreach_WithoutBraces_OnNextLine()
- {
- var original = @"
-using System;
-using System.Text;
-using System.Collections.Generic;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var list = new List();
- foreach (var item in list)
- Console.WriteLine(""true"");
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-using System.Collections.Generic;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var list = new List();
- foreach (var item in list)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, LoopStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_Foreach_WithBraces()
- {
- var original = @"
-using System;
-using System.Text;
-using System.Collections.Generic;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- var list = new List();
- foreach (var item in list)
- {
- Console.WriteLine(""true"");
- }
- }
- }
-}";
- VerifyDiagnostic(original);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_DoWhile_WithoutBraces_OnSameLine()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- do Console.WriteLine(""true""); while (true);
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- do
- {
- Console.WriteLine(""true"");
- }
- while (true);
- }
- }
-}";
-
- VerifyDiagnostic(original, LoopStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_DoWhile_WithoutBraces_OnSameLine_WithIntermittentComment()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- do /* comments */
- Console.WriteLine(""true"");
- while (true);
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- do /* comments */
- {
- Console.WriteLine(""true"");
- }
- while (true);
- }
- }
-}";
-
- VerifyDiagnostic(original, LoopStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_DoWhile_WithoutBraces_OnNextLine()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- do
- Console.WriteLine(""true"");
- while (true);
- }
- }
-}";
-
- var result = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- do
- {
- Console.WriteLine(""true"");
- }
- while (true);
- }
- }
-}";
-
- VerifyDiagnostic(original, LoopStatementWithoutBracesAnalyzer.Rule.MessageFormat.ToString());
- VerifyFix(original, result);
- }
-
- [TestMethod]
- public void LoopStatementWithoutBraces_DoWhile_WithBraces()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- do
- {
- Console.WriteLine(""true"");
- } while (true);
- }
- }
-}";
- VerifyDiagnostic(original);
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/LoopedRandomInstantiationTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/LoopedRandomInstantiationTests.cs
new file mode 100644
index 0000000..d9fc2b2
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/LoopedRandomInstantiationTests.cs
@@ -0,0 +1,259 @@
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.General.LoopedRandomInstantiation;
+
+namespace VSDiagnostics.Test.Tests.General
+{
+ [TestClass]
+ public class LoopedRandomInstantiationTests : CSharpDiagnosticVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new LoopedRandomInstantiationAnalyzer();
+
+ [TestMethod]
+ public void LoopedRandomInstantiation_WhileLoop()
+ {
+ var original = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ while (true)
+ {
+ var rand = new Random();
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(LoopedRandomInstantiationAnalyzer.Rule.MessageFormat.ToString(), "rand"));
+ }
+
+ [TestMethod]
+ public void LoopedRandomInstantiation_DoWhileLoop()
+ {
+ var original = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ do
+ {
+ var rand = new Random();
+ } while (true);
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(LoopedRandomInstantiationAnalyzer.Rule.MessageFormat.ToString(), "rand"));
+ }
+
+ [TestMethod]
+ public void LoopedRandomInstantiation_ForLoop()
+ {
+ var original = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ for (var i = 0; i > 5; i++)
+ {
+ var rand = new Random(4);
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(LoopedRandomInstantiationAnalyzer.Rule.MessageFormat.ToString(), "rand"));
+ }
+
+ [TestMethod]
+ public void LoopedRandomInstantiation_ForeachLoop()
+ {
+ var original = @"
+using System;
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ foreach (var item in list)
+ {
+ var rand = new Random();
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(LoopedRandomInstantiationAnalyzer.Rule.MessageFormat.ToString(), "rand"));
+ }
+
+ [TestMethod]
+ public void LoopedRandomInstantiation_MultipleDeclaratorsInDeclaration()
+ {
+ var original = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ while (true)
+ {
+ Random rand = new Random(), rind = new Random(2);
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(LoopedRandomInstantiationAnalyzer.Rule.MessageFormat.ToString(), "rand"),
+ string.Format(LoopedRandomInstantiationAnalyzer.Rule.MessageFormat.ToString(), "rind"));
+ }
+
+ [TestMethod]
+ public void LoopedRandomInstantiation_MultipleLevelsOfNesting()
+ {
+ var original = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ while (true)
+ {
+ if (true)
+ {
+ Random rand = new Random();
+ }
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(LoopedRandomInstantiationAnalyzer.Rule.MessageFormat.ToString(), "rand"));
+ }
+
+ [TestMethod]
+ public void LoopedRandomInstantiation_RandomInstanceNotInLoop()
+ {
+ var original = @"
+using System;
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var rand = new Random();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void LoopedRandomInstantiation_RandomNotSystemRandom()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class Random {}
+
+ class MyClass
+ {
+ void Method()
+ {
+ var rand = new Random();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void LoopedRandomInstantiation_TypeIsObject_DoesNotCrashAnalyzerBecauseContainingNamespaceIsNull()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ object[] o = {};
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void LoopedRandomInstantiation_Struct()
+ {
+ var original = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ void Method()
+ {
+ while (true)
+ {
+ var rand = new Random();
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(LoopedRandomInstantiationAnalyzer.Rule.MessageFormat.ToString(), "rand"));
+ }
+
+ [TestMethod]
+ public void LoopedRandomInstantiation_NotInLoop_Struct()
+ {
+ var original = @"
+using System;
+
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ void Method()
+ {
+ var rand = new Random();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+ }
+}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/MissingBracesTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/MissingBracesTests.cs
new file mode 100644
index 0000000..9a2fadd
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/MissingBracesTests.cs
@@ -0,0 +1,1662 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.General.MissingBraces;
+
+namespace VSDiagnostics.Test.Tests.General
+{
+ [TestClass]
+ public class MissingBracesTests : CSharpCodeFixVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new MissingBracesAnalyzer();
+
+ protected override CodeFixProvider CodeFixProvider => new MissingBracesCodeFix();
+
+ [TestMethod]
+ public void MissingBraces_IfWithoutBraces_OnSameLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true) Console.WriteLine(""true"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An if statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_IfWithoutBraces_OnSameLine_WithIntermittentComment()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true) /* comments */ Console.WriteLine(""true"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true) /* comments */
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An if statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_IfWithoutBraces_OnNextLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true)
+ Console.WriteLine(""true"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An if statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_IfWithBraces()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void MissingBraces_ElseStatementWithoutBraces_OnSameLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true)
+ {
+ Console.WriteLine(""true"");
+ }
+ else Console.WriteLine(""false"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true)
+ {
+ Console.WriteLine(""true"");
+ }
+ else
+ {
+ Console.WriteLine(""false"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An else statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_ElseStatementWithoutBraces_OnNextLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true)
+ {
+ Console.WriteLine(""true"");
+ }
+ else
+ Console.WriteLine(""false"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true)
+ {
+ Console.WriteLine(""true"");
+ }
+ else
+ {
+ Console.WriteLine(""false"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An else statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_ElseStatementWithBraces()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true)
+ {
+ Console.WriteLine(""true"");
+ }
+ else
+ {
+ Console.WriteLine(""false"");
+ }
+ }
+ }
+}";
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void MissingBraces_IfAndElseWithoutBraces()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true)
+ Console.WriteLine(""true"");
+ else
+ Console.WriteLine(""false"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ if(true)
+ {
+ Console.WriteLine(""true"");
+ }
+ else
+ {
+ Console.WriteLine(""false"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original,
+ "An if statement should be written with braces",
+ "An else statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_ElseIfWithBraces()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var i = 5;
+ if (i == 5)
+ {
+ Console.WriteLine(""true"");
+ }
+ else if (i == 4)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void MissingBraces_ElseIfWithoutBraces()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var i = 5;
+ if (i == 5)
+ {
+ Console.WriteLine(""true"");
+ }
+ else if (i == 4)
+ Console.WriteLine(""true"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var i = 5;
+ if (i == 5)
+ {
+ Console.WriteLine(""true"");
+ }
+ else if (i == 4)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "An if statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_UsingWithoutBraces_OnSameLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ using (var d = new Disposable()) Console.WriteLine(""true"");
+ }
+ }
+
+ class Disposable : IDisposable
+ {
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ using (var d = new Disposable())
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+
+ class Disposable : IDisposable
+ {
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A using statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_UsingWithoutBraces_OnSameLine_WithIntermittentComment()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ using (var d = new Disposable()) /* blah blah */ Console.WriteLine(""true"");
+ }
+ }
+
+ class Disposable : IDisposable
+ {
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ using (var d = new Disposable()) /* blah blah */
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+
+ class Disposable : IDisposable
+ {
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A using statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_UsingWithoutBraces_OnNextLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ using (var d = new Disposable())
+ Console.WriteLine(""true"");
+ }
+ }
+
+ class Disposable : IDisposable
+ {
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ using (var d = new Disposable())
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+
+ class Disposable : IDisposable
+ {
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A using statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_UsingWithBraces()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ using (var d = new Disposable())
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+
+ class Disposable : IDisposable
+ {
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void MissingBraces_WithOutBraces_ChildIsUsingStatement()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ using (var d = new Disposable())
+ using (var e = new Disposable())
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+
+ class Disposable : IDisposable
+ {
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void MissingBraces_WithOutBraces_ChildIsUsingStatementWithBraces()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ using (var d = new Disposable())
+ using (var e = new Disposable())
+ Console.WriteLine(""true"");
+ }
+ }
+
+ class Disposable : IDisposable
+ {
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ using (var d = new Disposable())
+ using (var e = new Disposable())
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+
+ class Disposable : IDisposable
+ {
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A using statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_For_WithoutBraces_OnSameLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ for (int i = 0; i < 10; i++) Console.WriteLine(""true"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A for statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_For_WithoutBraces_OnSameLine_WithIntermittentComment()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ for (int i = 0; i < 10; i++) /* comments */ Console.WriteLine(""true"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ for (int i = 0; i < 10; i++) /* comments */
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A for statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_For_WithoutBraces_OnNextLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ for (int i = 0; i < 10; i++)
+ Console.WriteLine(""true"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A for statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_For_WithBraces()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void MissingBraces_While_WithoutBraces_OnSameLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ while (true) Console.WriteLine(""true"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ while (true)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A while statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_While_WithoutBraces_OnSameLine_WithIntermittentComment()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ while (true) /* comments */ Console.WriteLine(""true"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ while (true) /* comments */
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A while statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_While_WithoutBraces_OnNextLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ while (true)
+ Console.WriteLine(""true"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ while (true)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A while statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_While_WithBraces()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ while (true)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void MissingBraces_Foreach_WithoutBraces_OnSameLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ foreach (var item in list) Console.WriteLine(""true"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ foreach (var item in list)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A foreach statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_Foreach_WithoutBraces_OnSameLine_WithIntermittentComment()
+ {
+ var original = @"
+using System;
+using System.Text;
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ foreach (var item in list) /* comments */ Console.WriteLine(""true"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ foreach (var item in list) /* comments */
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A foreach statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_Foreach_WithoutBraces_OnNextLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ foreach (var item in list)
+ Console.WriteLine(""true"");
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ foreach (var item in list)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A foreach statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_Foreach_WithBraces()
+ {
+ var original = @"
+using System;
+using System.Text;
+using System.Collections.Generic;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var list = new List();
+ foreach (var item in list)
+ {
+ Console.WriteLine(""true"");
+ }
+ }
+ }
+}";
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void MissingBraces_DoWhile_WithoutBraces_OnSameLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ do Console.WriteLine(""true""); while (true);
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ do
+ {
+ Console.WriteLine(""true"");
+ }
+ while (true);
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A do statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_DoWhile_WithoutBraces_OnSameLine_WithIntermittentComment()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ do /* comments */
+ Console.WriteLine(""true"");
+ while (true);
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ do /* comments */
+ {
+ Console.WriteLine(""true"");
+ }
+ while (true);
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A do statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_DoWhile_WithoutBraces_OnNextLine()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ do
+ Console.WriteLine(""true"");
+ while (true);
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ do
+ {
+ Console.WriteLine(""true"");
+ }
+ while (true);
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A do statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_DoWhile_WithBraces()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ do
+ {
+ Console.WriteLine(""true"");
+ } while (true);
+ }
+ }
+}";
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void MissingBraces_Lock_WithoutBraces()
+ {
+ var original = @"
+class Program
+{
+ static void Main()
+ {
+ var str = ""test"";
+ lock (str)
+ return;
+ }
+}";
+
+ var result = @"
+class Program
+{
+ static void Main()
+ {
+ var str = ""test"";
+ lock (str)
+ {
+ return;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A lock statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_Lock_WithoutBraces_NestedInLock()
+ {
+ var original = @"
+class Program
+{
+ static void Main()
+ {
+ var str1 = ""test"";
+ var str2 = ""test"";
+ lock (str1)
+ lock (str2) // VS thinks this should be indented one more level
+ return;
+ }
+}";
+
+ var result = @"
+class Program
+{
+ static void Main()
+ {
+ var str1 = ""test"";
+ var str2 = ""test"";
+ lock (str1)
+ lock (str2) // VS thinks this should be indented one more level
+ {
+ return;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A lock statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_Lock_WithBraces()
+ {
+ var original = @"
+class Program
+{
+ static void Main()
+ {
+ var str = ""test"";
+ lock (str)
+ {
+ return;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [Ignore] // need unsafe compilation option
+ [TestMethod]
+ public void MissingBraces_Fixed_WithoutBraces()
+ {
+ var original = @"
+class Point
+{
+ public int x;
+ public int y;
+}
+
+class Program
+{
+ unsafe static void TestMethod()
+ {
+ var pt = new Point();
+ fixed (int* p = &pt.x)
+ *p = 1;
+ }
+}";
+
+ var result = @"
+class Point
+{
+ public int x;
+ public int y;
+}
+
+class Program
+{
+ unsafe static void TestMethod()
+ {
+ var pt = new Point();
+ fixed (int* p = &pt.x)
+ {
+ *p = 1;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A fixed statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [Ignore] // need unsafe compilation option
+ [TestMethod]
+ public void MissingBraces_Fixed_WithoutBraces_NestedInFixed()
+ {
+ var original = @"
+class Point
+{
+ public int x;
+ public int y;
+}
+
+class Program
+{
+ unsafe static void TestMethod()
+ {
+ var pt = new Point();
+ fixed (int* p = &pt.x)
+ fixed (int* q = &pt.y)
+ *p = 1;
+ }
+}";
+
+ var result = @"
+class Point
+{
+ public int x;
+ public int y;
+}
+
+class Program
+{
+ unsafe static void TestMethod()
+ {
+ var pt = new Point();
+ fixed (int* p = &pt.x)
+ fixed (int* q = &pt.y)
+ {
+ *p = 1;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A fixed statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [Ignore] // need unsafe compilation option
+ [TestMethod]
+ public void MissingBraces_Fixed_WithBraces()
+ {
+ var original = @"
+class Point
+{
+ public int x;
+ public int y;
+}
+
+class Program
+{
+ unsafe static void TestMethod()
+ {
+ var pt = new Point();
+ fixed (int* p = &pt.x)
+ {
+ *p = 1;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void MissingBraces_CaseLabel_WithoutBraces()
+ {
+ var original = @"
+class Program
+{
+ static void Main()
+ {
+ var str = ""test"";
+ switch (str)
+ {
+ case ""test"":
+ return;
+ }
+ }
+}";
+
+ var result = @"
+class Program
+{
+ static void Main()
+ {
+ var str = ""test"";
+ switch (str)
+ {
+ case ""test"":
+ {
+ return;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A switch section statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_CaseLabel_WithoutBraces_ManyChildStatements()
+ {
+ var original = @"
+class Program
+{
+ static int Test()
+ {
+ var str = ""test"";
+ switch (str)
+ {
+ case ""test"":
+ var i = 0;
+ i = str.GetHashCode();
+ return i;
+ }
+ return 0;
+ }
+}";
+
+ var result = @"
+class Program
+{
+ static int Test()
+ {
+ var str = ""test"";
+ switch (str)
+ {
+ case ""test"":
+ {
+ var i = 0;
+ i = str.GetHashCode();
+ return i;
+ }
+ }
+ return 0;
+ }
+}";
+
+ VerifyDiagnostic(original, "A switch section statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_DefaultLabel_WithoutBraces()
+ {
+ var original = @"
+class Program
+{
+ static void Main()
+ {
+ var str = ""test"";
+ switch (str)
+ {
+ default:
+ return;
+ }
+ }
+}";
+
+ var result = @"
+class Program
+{
+ static void Main()
+ {
+ var str = ""test"";
+ switch (str)
+ {
+ default:
+ {
+ return;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "A switch section statement should be written with braces");
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void MissingBraces_CaseLabel_WithBraces()
+ {
+ var original = @"
+class Program
+{
+ static void Main()
+ {
+ var str = ""test"";
+ switch (str)
+ {
+ case ""test"":
+ {
+ return;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void MissingBraces_DefaultLabel_WithBraces()
+ {
+ var original = @"
+class Program
+{
+ static void Main()
+ {
+ var str = ""test"";
+ switch (str)
+ {
+ default:
+ {
+ return;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/NonEncapsulatedOrMutableFieldTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/NonEncapsulatedOrMutableFieldTests.cs
index 32bb487..0d41175 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/NonEncapsulatedOrMutableFieldTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/NonEncapsulatedOrMutableFieldTests.cs
@@ -369,6 +369,57 @@ class MyClass
VerifyFix(original, result);
}
+ [TestMethod]
+ public void NonEncapsulatedOrMutableField_Param()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int myField;
+
+ void DoSomething()
+ {
+ MyMethod(myField);
+ }
+
+ void MyMethod(int x)
+ {
+
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int myField { get; set; }
+
+ void DoSomething()
+ {
+ MyMethod(myField);
+ }
+
+ void MyMethod(int x)
+ {
+
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(NonEncapsulatedOrMutableFieldAnalyzer.Rule.MessageFormat.ToString(), "myField"));
+ VerifyFix(original, result);
+ }
+
[TestMethod]
public void NonEncapsulatedOrMutableField_Ref()
{
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/RedudantPrivateSetterTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/RedudantPrivateSetterTests.cs
new file mode 100644
index 0000000..6fa9a22
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/RedudantPrivateSetterTests.cs
@@ -0,0 +1,358 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.General.RedundantPrivateSetter;
+
+namespace VSDiagnostics.Test.Tests.General
+{
+ [TestClass]
+ public class RedundantPrivateSetterTests : CSharpCodeFixVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new RedundantPrivateSetterAnalyzer();
+
+ protected override CodeFixProvider CodeFixProvider => new RedundantPrivateSetterCodeFix();
+
+ [TestMethod]
+ public void RedundantPrivateSetter()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int MyProperty { get; private set; }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int MyProperty { get; }
+ }
+}";
+
+ VerifyDiagnostic(original,
+ string.Format(RedundantPrivateSetterAnalyzer.Rule.MessageFormat.ToString(), "MyProperty"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void RedundantPrivateSetter_ConstructorUsage()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int MyProperty { get; private set; }
+
+ public MyClass()
+ {
+ MyProperty = 42;
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int MyProperty { get; }
+
+ public MyClass()
+ {
+ MyProperty = 42;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original,
+ string.Format(RedundantPrivateSetterAnalyzer.Rule.MessageFormat.ToString(), "MyProperty"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void RedundantPrivateSetter_NonConstructorUsage()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int MyProperty { get; private set; }
+
+ public void MyMethod()
+ {
+ MyProperty = 42;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void RedundantPrivateSetter_ConstructorAndNonConstructorUsage()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int MyProperty { get; private set; }
+
+ public MyClass()
+ {
+ MyProperty = 42;
+ }
+
+ public void Method()
+ {
+ MyProperty = 69;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void RedundantPrivateSetter_NonPrivateAccessibility()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int MyProperty { get; protected set; }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void RedundantPrivateSetter_NoAccessibility()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int MyProperty { get; set; }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void RedundantPrivateSetter_NoSetter()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int MyProperty { get; }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void RedundantPrivateSetter_ExpressionBodiedProperty()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int MyProperty => 5;
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void RedundantPrivateSetter_NonConstructorReading()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int MyProperty { get; private set; }
+
+ public void MyMethod()
+ {
+ if(MyProperty > 5)
+ {
+
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int MyProperty { get; }
+
+ public void MyMethod()
+ {
+ if(MyProperty > 5)
+ {
+
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original,
+ string.Format(RedundantPrivateSetterAnalyzer.Rule.MessageFormat.ToString(), "MyProperty"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void RedundantPrivateSetter_PartialClass()
+ {
+ var firstTree = @"
+namespace ConsoleApplication1
+{
+ partial class MyClass
+ {
+ public int MyProperty { get; private set; }
+
+ public MyClass()
+ {
+ MyProperty = 42;
+ }
+ }
+}";
+
+ var secondTree = @"
+namespace ConsoleApplication1
+{
+ partial class MyClass
+ {
+ public void MyMethod()
+ {
+ MyProperty = 42;
+ }
+ }
+}";
+
+ VerifyDiagnostic(new[] {firstTree, secondTree});
+ }
+
+ [TestMethod]
+ public void RedundantPrivateSetter_PartialClass_IrrelevantIdentifier()
+ {
+ var firstTree = @"
+namespace ConsoleApplication1
+{
+ partial class MyClass
+ {
+ public int MyProperty { get; private set; }
+
+ public MyClass()
+ {
+ MyProperty = 42;
+ }
+ }
+}";
+
+ var secondTree = @"
+namespace ConsoleApplication1
+{
+ partial class MyClass
+ {
+ public void MyMethod()
+ {
+ var MyProperty = 42;
+ }
+ }
+}";
+
+ VerifyDiagnostic(new[] { firstTree, secondTree }, string.Format(RedundantPrivateSetterAnalyzer.Rule.MessageFormat.ToString(), "MyProperty"));
+ }
+
+ [TestMethod]
+ public void RedundantPrivateSetter_StaticNonConstructorUsage()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public static int MyProperty { get; private set; }
+
+ public static void MyMethod()
+ {
+ MyProperty = 42;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void RedundantPrivateSetter_Indexer()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public string this[int i]
+ {
+ get
+ {
+ return string.Empty;
+ }
+
+ private set { }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void RedundantPrivateSetter_Struct()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ public int MyProperty { get; private set; }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ struct MyStruct
+ {
+ public int MyProperty { get; }
+ }
+}";
+
+ VerifyDiagnostic(original,
+ string.Format(RedundantPrivateSetterAnalyzer.Rule.MessageFormat.ToString(), "MyProperty"));
+ VerifyFix(original, result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/SimplifyExpressionBodiedMemberTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/SimplifyExpressionBodiedMemberTests.cs
index 32da872..aa3b22a 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/SimplifyExpressionBodiedMemberTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/SimplifyExpressionBodiedMemberTests.cs
@@ -907,6 +907,26 @@ void MyMethod()
throw new NotImplementedException();
}
}
+}";
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void SimplifyExpressionBodiedMember_WithVoidMethod_EmptyReturn()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void MyMethod()
+ {
+ return;
+ }
+ }
}";
VerifyDiagnostic(original);
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/SwitchDoesNotHandleAllEnumOptionsTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/SwitchDoesNotHandleAllEnumOptionsTests.cs
new file mode 100644
index 0000000..4a39f9f
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/SwitchDoesNotHandleAllEnumOptionsTests.cs
@@ -0,0 +1,1019 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.General.SwitchDoesNotHandleAllEnumOptions;
+
+namespace VSDiagnostics.Test.Tests.General
+{
+ [TestClass]
+ public class SwitchDoesNotHandleAllEnumOptionsTests : CSharpCodeFixVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new SwitchDoesNotHandleAllEnumOptionsAnalyzer();
+ protected override CodeFixProvider CodeFixProvider => new SwitchDoesNotHandleAllEnumOptionsCodeFix();
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_MissingEnumStatement()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.Fizz:
+ case MyEnum.Buzz:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.FizzBuzz:
+ throw new System.NotImplementedException();
+ case MyEnum.Fizz:
+ case MyEnum.Buzz:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_AllEnumStatements()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.Fizz:
+ case MyEnum.Buzz:
+ case MyEnum.FizzBuzz:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_CaseStatementsNotEnum()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ switch (""test"")
+ {
+ case ""Fizz"":
+ case ""Buzz"":
+ case ""FizzBuzz"":
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_CaseHasDefaultStatement_NewStatementsAreAddedAboveDefault()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ default:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.FizzBuzz:
+ throw new System.NotImplementedException();
+ case MyEnum.Buzz:
+ throw new System.NotImplementedException();
+ case MyEnum.Fizz:
+ throw new System.NotImplementedException();
+ default:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_MissingEnumStatement_MultipleSections()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.Fizz:
+ break;
+ case MyEnum.Buzz:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.FizzBuzz:
+ throw new System.NotImplementedException();
+ case MyEnum.Fizz:
+ break;
+ case MyEnum.Buzz:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_UsingStaticEnum_MissingEnumStatements()
+ {
+ var original = @"
+using System.IO;
+using static System.IO.FileOptions;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ case Asynchronous:
+ case DeleteOnClose:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+using System.IO;
+using static System.IO.FileOptions;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ case Encrypted:
+ throw new System.NotImplementedException();
+ case SequentialScan:
+ throw new System.NotImplementedException();
+ case RandomAccess:
+ throw new System.NotImplementedException();
+ case WriteThrough:
+ throw new System.NotImplementedException();
+ case None:
+ throw new System.NotImplementedException();
+ case Asynchronous:
+ case DeleteOnClose:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_MissingEnumStatement_AddsAllMissingStatements()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.Buzz:
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.FizzBuzz:
+ throw new System.NotImplementedException();
+ case MyEnum.Fizz:
+ throw new System.NotImplementedException();
+ case MyEnum.Buzz:
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_UsingStaticEnum_NoEnumStatements()
+ {
+ var original = @"
+using System.IO;
+using static System.IO.FileOptions;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ }
+ }
+ }
+}";
+
+ var result = @"
+using System.IO;
+using static System.IO.FileOptions;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ case Encrypted:
+ throw new System.NotImplementedException();
+ case SequentialScan:
+ throw new System.NotImplementedException();
+ case DeleteOnClose:
+ throw new System.NotImplementedException();
+ case RandomAccess:
+ throw new System.NotImplementedException();
+ case Asynchronous:
+ throw new System.NotImplementedException();
+ case WriteThrough:
+ throw new System.NotImplementedException();
+ case None:
+ throw new System.NotImplementedException();
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_UsingStaticEnum_MissingEnumStatement_MixedExpandedEnumStatements()
+ {
+ var original = @"
+using System.IO;
+using static System.IO.FileOptions;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ case FileOptions.Encrypted:
+ break;
+ case SequentialScan:
+ break;
+ case RandomAccess:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+using System.IO;
+using static System.IO.FileOptions;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ case DeleteOnClose:
+ throw new System.NotImplementedException();
+ case Asynchronous:
+ throw new System.NotImplementedException();
+ case WriteThrough:
+ throw new System.NotImplementedException();
+ case None:
+ throw new System.NotImplementedException();
+ case Encrypted:
+ break;
+ case SequentialScan:
+ break;
+ case RandomAccess:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result, allowedNewCompilerDiagnosticsId: "CS8019"); // unneeded using directive
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_UsingStaticEnum_MissingEnumStatement_AllExpandedEnumStatements()
+ {
+ var original = @"
+using System.IO;
+using static System.IO.FileOptions;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ case FileOptions.Encrypted:
+ break;
+ case FileOptions.SequentialScan:
+ break;
+ case FileOptions.RandomAccess:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+using System.IO;
+using static System.IO.FileOptions;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ case FileOptions.DeleteOnClose:
+ throw new System.NotImplementedException();
+ case FileOptions.Asynchronous:
+ throw new System.NotImplementedException();
+ case FileOptions.WriteThrough:
+ throw new System.NotImplementedException();
+ case FileOptions.None:
+ throw new System.NotImplementedException();
+ case FileOptions.Encrypted:
+ break;
+ case FileOptions.SequentialScan:
+ break;
+ case FileOptions.RandomAccess:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_MissingEnumStatement_NoRedundantQualifierIfUsingSystemDirectiveExists()
+ {
+ var original = @"
+using System;
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.Fizz:
+ case MyEnum.Buzz:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+using System;
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.FizzBuzz:
+ throw new NotImplementedException();
+ case MyEnum.Fizz:
+ case MyEnum.Buzz:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_MissingEnumStatement_UsingAliasForSystem()
+ {
+ var original = @"
+using Fizz = System; // seriously...
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.Fizz:
+ case MyEnum.Buzz:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+using Fizz = System; // seriously...
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.FizzBuzz:
+ throw new Fizz.NotImplementedException();
+ case MyEnum.Fizz:
+ case MyEnum.Buzz:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_UsingStaticEnum_MissingEnumStatement_SimplifiesAllStatementsWhenParentDirectiveNotIncluded()
+ {
+ var original = @"
+using static System.IO.FileOptions;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ case Encrypted:
+ break;
+ case SequentialScan:
+ break;
+ case RandomAccess:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+using static System.IO.FileOptions;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ case DeleteOnClose:
+ throw new System.NotImplementedException();
+ case Asynchronous:
+ throw new System.NotImplementedException();
+ case WriteThrough:
+ throw new System.NotImplementedException();
+ case None:
+ throw new System.NotImplementedException();
+ case Encrypted:
+ break;
+ case SequentialScan:
+ break;
+ case RandomAccess:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_UsingStaticEnum_MissingEnumStatement_SimplifiesAllStatementsWhenUsingDirectiveIncludesWhitespace()
+ {
+ var original = @"
+using static System . IO . FileOptions; // Happy maintaining
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ case Encrypted:
+ break;
+ case SequentialScan:
+ break;
+ case RandomAccess:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+using static System . IO . FileOptions; // Happy maintaining
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ case DeleteOnClose:
+ throw new System.NotImplementedException();
+ case Asynchronous:
+ throw new System.NotImplementedException();
+ case WriteThrough:
+ throw new System.NotImplementedException();
+ case None:
+ throw new System.NotImplementedException();
+ case Encrypted:
+ break;
+ case SequentialScan:
+ break;
+ case RandomAccess:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_MissingEnumStatement_NestedEnum()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.Fizz:
+ case MyEnum.Buzz:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.FizzBuzz:
+ throw new System.NotImplementedException();
+ case MyEnum.Fizz:
+ case MyEnum.Buzz:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_MissingEnumStatements_CaseValueIsCastToEnumType()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case (MyEnum) 0:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_NoCaseStatements_NoUsings()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = System.IO.FileOptions.DeleteOnClose;
+ switch (e)
+ {
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = System.IO.FileOptions.DeleteOnClose;
+ switch (e)
+ {
+ case System.IO.FileOptions.Encrypted:
+ throw new System.NotImplementedException();
+ case System.IO.FileOptions.SequentialScan:
+ throw new System.NotImplementedException();
+ case System.IO.FileOptions.DeleteOnClose:
+ throw new System.NotImplementedException();
+ case System.IO.FileOptions.RandomAccess:
+ throw new System.NotImplementedException();
+ case System.IO.FileOptions.Asynchronous:
+ throw new System.NotImplementedException();
+ case System.IO.FileOptions.WriteThrough:
+ throw new System.NotImplementedException();
+ case System.IO.FileOptions.None:
+ throw new System.NotImplementedException();
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_NoCaseStatements_NormalUsing()
+ {
+ var original = @"
+using System.IO;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = FileOptions.DeleteOnClose;
+ switch (e)
+ {
+ }
+ }
+ }
+}";
+
+ var result = @"
+using System.IO;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = FileOptions.DeleteOnClose;
+ switch (e)
+ {
+ case FileOptions.Encrypted:
+ throw new System.NotImplementedException();
+ case FileOptions.SequentialScan:
+ throw new System.NotImplementedException();
+ case FileOptions.DeleteOnClose:
+ throw new System.NotImplementedException();
+ case FileOptions.RandomAccess:
+ throw new System.NotImplementedException();
+ case FileOptions.Asynchronous:
+ throw new System.NotImplementedException();
+ case FileOptions.WriteThrough:
+ throw new System.NotImplementedException();
+ case FileOptions.None:
+ throw new System.NotImplementedException();
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchDoesNotHandleAllEnumOptions_NoCaseStatements_UsingStatic()
+ {
+ var original = @"
+using static System.IO.FileOptions;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ }
+ }
+ }
+}";
+
+ var result = @"
+using static System.IO.FileOptions;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = DeleteOnClose;
+ switch (e)
+ {
+ case Encrypted:
+ throw new System.NotImplementedException();
+ case SequentialScan:
+ throw new System.NotImplementedException();
+ case DeleteOnClose:
+ throw new System.NotImplementedException();
+ case RandomAccess:
+ throw new System.NotImplementedException();
+ case Asynchronous:
+ throw new System.NotImplementedException();
+ case WriteThrough:
+ throw new System.NotImplementedException();
+ case None:
+ throw new System.NotImplementedException();
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchDoesNotHandleAllEnumOptionsAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/SwitchIsMissingDefaultLabelTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/SwitchIsMissingDefaultLabelTests.cs
new file mode 100644
index 0000000..5101334
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/SwitchIsMissingDefaultLabelTests.cs
@@ -0,0 +1,357 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.General.SwitchIsMissingDefaultLabel;
+
+namespace VSDiagnostics.Test.Tests.General
+{
+ [TestClass]
+ public class SwitchIsMissingDefaultLabelTests : CSharpCodeFixVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new SwitchIsMissingDefaultLabelAnalyzer();
+ protected override CodeFixProvider CodeFixProvider => new SwitchIsMissingDefaultLabelCodeFix();
+
+ [TestMethod]
+ public void SwitchIsMissingDefaultLabel_MissingDefaultStatement_SwitchOnEnum()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.Fizz:
+ case MyEnum.Buzz:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ enum MyEnum
+ {
+ Fizz, Buzz, FizzBuzz
+ }
+
+ class MyClass
+ {
+ void Method()
+ {
+ var e = MyEnum.Fizz;
+ switch (e)
+ {
+ case MyEnum.Fizz:
+ case MyEnum.Buzz:
+ break;
+ default:
+ throw new System.ArgumentException(nameof(e));
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchIsMissingDefaultLabelAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchIsMissingDefaultLabel_MissingDefaultStatement_SwitchOnString()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = ""test"";
+ switch (e)
+ {
+ case ""test"":
+ case ""test1"":
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = ""test"";
+ switch (e)
+ {
+ case ""test"":
+ case ""test1"":
+ break;
+ default:
+ throw new System.ArgumentException(nameof(e));
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchIsMissingDefaultLabelAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchIsMissingDefaultLabel_MissingDefaultStatement_SwitchOnStringLiteral()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ switch (""test"")
+ {
+ case ""test"":
+ case ""test1"":
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ switch (""test"")
+ {
+ case ""test"":
+ case ""test1"":
+ break;
+ default:
+ throw new System.ArgumentException(""test"");
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchIsMissingDefaultLabelAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchIsMissingDefaultLabel_MissingDefaultStatement_SwitchOnIntegerLiteral()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ switch (0)
+ {
+ case 0:
+ case 1:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ switch (0)
+ {
+ case 0:
+ case 1:
+ break;
+ default:
+ throw new System.ArgumentException(0.ToString());
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchIsMissingDefaultLabelAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchIsMissingDefaultLabel_HasDefaultStatement()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var e = ""test"";
+ switch (e)
+ {
+ case ""test"":
+ case ""test1"":
+ default:
+ break;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void SwitchIsMissingDefaultLabel_MissingDefaultStatement_ParenthesizedStatement()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var x = 5;
+ switch ((x))
+ {
+ case 5:
+ case 6:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var x = 5;
+ switch ((x))
+ {
+ case 5:
+ case 6:
+ break;
+ default:
+ throw new System.ArgumentException(nameof(x));
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchIsMissingDefaultLabelAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchIsMissingDefaultLabel_MissingDefaultStatement_SwitchOnParenthsizedStringLiteral()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ switch ((""test""))
+ {
+ case ""test"":
+ case ""test1"":
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ switch ((""test""))
+ {
+ case ""test"":
+ case ""test1"":
+ break;
+ default:
+ throw new System.ArgumentException((""test"").ToString());
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchIsMissingDefaultLabelAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void SwitchIsMissingDefaultLabel_MissingDefaultStatement_SwitchOnParenthsizedIntegerLiteral()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ switch ((0))
+ {
+ case 0:
+ case 1:
+ break;
+ }
+ }
+ }
+}";
+
+ var result = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ switch ((0))
+ {
+ case 0:
+ case 1:
+ break;
+ default:
+ throw new System.ArgumentException((0).ToString());
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, SwitchIsMissingDefaultLabelAnalyzer.Rule.MessageFormat.ToString());
+ VerifyFix(original, result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/TryCastUsingAsNotNullInsteadOfIsAsTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/TryCastUsingAsNotNullInsteadOfIsAsTests.cs
index 74c70bc..a0a19b8 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/TryCastUsingAsNotNullInsteadOfIsAsTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/TryCastUsingAsNotNullInsteadOfIsAsTests.cs
@@ -456,52 +456,6 @@ void Method()
VerifyDiagnostic(original);
}
- [TestMethod]
- public void TryCastWithoutUsingAsNotNull_ChainedVariableDeclaration()
- {
- var original = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- object o = 5;
- if (o is int)
- {
- int? oAsInt = o as int?, x = 10;
- }
- }
- }
-}";
-
- var expected = @"
-using System;
-using System.Text;
-
-namespace ConsoleApplication1
-{
- class MyClass
- {
- void Method()
- {
- object o = 5;
- var oAsInt32 = o as int?;
- if (oAsInt32 != null)
- {
- int? x = 10;
- }
- }
- }
-}";
-
- VerifyDiagnostic(original, string.Format(TryCastWithoutUsingAsNotNullAnalyzer.Rule.MessageFormat.ToString(), "o"));
- VerifyFix(original, expected);
- }
-
[TestMethod]
public void TryCastWithoutUsingAsNotNull_TryCastNullCheck()
{
@@ -570,7 +524,8 @@ void Method()
}
}";
- VerifyDiagnostic(original, string.Format(TryCastWithoutUsingAsNotNullAnalyzer.Rule.MessageFormat.ToString(), "o"),
+ VerifyDiagnostic(original,
+ string.Format(TryCastWithoutUsingAsNotNullAnalyzer.Rule.MessageFormat.ToString(), "o"),
string.Format(TryCastWithoutUsingAsNotNullAnalyzer.Rule.MessageFormat.ToString(), "o"));
VerifyFix(original, expected);
}
@@ -1751,5 +1706,577 @@ void Method(object o)
VerifyDiagnostic(original, string.Format(TryCastWithoutUsingAsNotNullAnalyzer.Rule.MessageFormat.ToString(), "o"));
VerifyFix(original, expected);
}
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_TernaryOperator()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ var x = o is int ? 5 : 6;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_TernaryOperator_WithCasts()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ var x = o is int ? ((int) o) : ((double) o);
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_Return()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ object Method(object o)
+ {
+ return o is int ? 5 : 6;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_Return_WithCasts()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ object Method(object o)
+ {
+ return o is int ? ((int) o) : ((double) o);
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_Return_IsStatement()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ bool Method(object o)
+ {
+ return o is int;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_Local()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ var isInt = o is int;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_IrrelevantIfParent()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ if (true)
+ {
+ var res = o is int ? ((int)o) : ((double)o);
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_IrrelevantIfParent_2()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ if (true)
+ {
+ if (true)
+ {
+ var res = o is int ? ((int)o) : ((double)o);
+ }
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_IrrelevantIfAncestor()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ object o = ""sample"";
+ if (true)
+ {
+ if (o is string)
+ {
+ string oAsString = o as string;
+ }
+ }
+ }
+ }
+}";
+
+ var expected = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ object o = ""sample"";
+ if (true)
+ {
+ var oAsString = o as string;
+ if (oAsString != null)
+ {
+ }
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(TryCastWithoutUsingAsNotNullAnalyzer.Rule.MessageFormat.ToString(), "o"));
+ VerifyFix(original, expected);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_Trivia()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ object o = ""sample"";
+ if (o is string)
+ {
+ // Test
+ string oAsString = o as string; // Test
+ }
+ }
+ }
+}";
+
+ var expected = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ object o = ""sample"";
+ var oAsString = o as string;
+ if (oAsString != null)
+ {
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(TryCastWithoutUsingAsNotNullAnalyzer.Rule.MessageFormat.ToString(), "o"));
+ VerifyFix(original, expected);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_MultipleDeclarators()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ object o = ""sample"";
+ if (o is string)
+ {
+ string oAsString = o as string, s = ""test"";
+ }
+ }
+ }
+}";
+
+ var expected = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ object o = ""sample"";
+ var oAsString = o as string;
+ if (oAsString != null)
+ {
+ string s = ""test"";
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(TryCastWithoutUsingAsNotNullAnalyzer.Rule.MessageFormat.ToString(), "o"));
+ VerifyFix(original, expected);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_TernaryWithAppropriateIfCondition()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ int x, y;
+
+ void Method(object o)
+ {
+ if (o is int)
+ {
+ var res = x > y ? (int) o : (double) o;
+ }
+ }
+ }
+}";
+
+ var expected = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ int x, y;
+
+ void Method(object o)
+ {
+ var oAsInt32 = o as int?;
+ if (oAsInt32 != null)
+ {
+ var res = x > y ? oAsInt32.Value : (double) o;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(TryCastWithoutUsingAsNotNullAnalyzer.Rule.MessageFormat.ToString(), "o"));
+ VerifyFix(original, expected);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_TernaryWithAppropriateIfCondition_RepeatedCheck()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ if (o is int)
+ {
+ var res = o is int ? (int) o : (double) o;
+ }
+ }
+ }
+}";
+
+ var expected = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ var oAsInt32 = o as int?;
+ if (oAsInt32 != null)
+ {
+ var res = o is int ? oAsInt32.Value : (double) o;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(TryCastWithoutUsingAsNotNullAnalyzer.Rule.MessageFormat.ToString(), "o"));
+ VerifyFix(original, expected);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_DirectCastAndTryCast()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ if (o is int)
+ {
+ var res = o is int ? (int) o : o as double?;
+ }
+ }
+ }
+}";
+
+ var expected = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ var oAsInt32 = o as int?;
+ if (oAsInt32 != null)
+ {
+ var res = o is int ? oAsInt32.Value : o as double?;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(TryCastWithoutUsingAsNotNullAnalyzer.Rule.MessageFormat.ToString(), "o"));
+ VerifyFix(original, expected);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_RedundantCheck()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ if (o is int)
+ {
+ var x = (int) o;
+ var y = o is int;
+ }
+ }
+ }
+}";
+
+ var expected = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ var oAsInt32 = o as int?;
+ if (oAsInt32 != null)
+ {
+ var y = o is int;
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(TryCastWithoutUsingAsNotNullAnalyzer.Rule.MessageFormat.ToString(), "o"));
+ VerifyFix(original, expected);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_While()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ if (true)
+ {
+ while(o is int)
+ {
+ var x = o as int?;
+ o = ""test"";
+ }
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void TryCastWithoutUsingAsNotNull_NegativeCondition()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ if (!(o is int))
+ {
+ var x = o as int?;
+ }
+ }
+ }
+}";
+
+ var expected = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(object o)
+ {
+ var oAsInt32 = o as int?;
+ if (!(oAsInt32 != null))
+ {
+ }
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(TryCastWithoutUsingAsNotNullAnalyzer.Rule.MessageFormat.ToString(), "o"));
+ VerifyFix(original, expected);
+ }
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/TypeToVarTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/TypeToVarTests.cs
index 6d80e32..cfd134f 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/TypeToVarTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/TypeToVarTests.cs
@@ -280,5 +280,46 @@ void Method()
VerifyDiagnostic(original);
}
+
+ [TestMethod]
+ public void TypeToVar_WithLambdaExpression_NoType()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ Action x = () => { };
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void TypeToVar_WithLocalDefinedWithDynamic()
+ {
+ var original = @"
+using System.Dynamic;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ dynamic exceptionInfo = new ExpandoObject();
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/UseAliasesInsteadOfConcreteTypeTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/UseAliasesInsteadOfConcreteTypeTests.cs
index 4bbc275..ac632e4 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/UseAliasesInsteadOfConcreteTypeTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/UseAliasesInsteadOfConcreteTypeTests.cs
@@ -940,7 +940,7 @@ namespace ConsoleApplication1
{
class MyClass
{
- public static explicit operator int(MyClass c)
+ public static explicit operator int (MyClass c)
{
return 5;
}
@@ -1571,7 +1571,7 @@ static void Main() { }
}
[TestMethod]
- public void UseAliasesInsteadOfConcreteType_DisplaysCorrectWarning()
+ public void UseAliasesInsteadOfConcreteType_DoesNotDisplayWarningWithAlias()
{
var original = @"
using Single = System.String;
@@ -1587,22 +1587,7 @@ static void Main()
}
}";
- var result = @"
-using Single = System.String;
-
-namespace ConsoleApplication1
-{
- class Foo
- {
- static void Main()
- {
- string bar = ""test"";
- }
- }
-}";
-
- VerifyDiagnostic(original, string.Format(UseAliasesInsteadOfConcreteTypeAnalyzer.Rule.MessageFormat.ToString(), "string", "String"));
- VerifyFix(original, result, allowNewCompilerDiagnostics: true);
+ VerifyDiagnostic(original);
}
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Structs/StructMutateSelfTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Structs/StructMutateSelfTests.cs
index 5f09140..30444be 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Structs/StructMutateSelfTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Structs/StructMutateSelfTests.cs
@@ -1,7 +1,6 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RoslynTester.Helpers.CSharp;
-using VSDiagnostics.Diagnostics.Structs;
using VSDiagnostics.Diagnostics.Structs.StructShouldNotMutateSelf;
namespace VSDiagnostics.Test.Tests.Structs
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Structs/StructWithoutElementaryMethodsOverriddenTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Structs/StructWithoutElementaryMethodsOverriddenTests.cs
new file mode 100644
index 0000000..5b1ba0f
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Structs/StructWithoutElementaryMethodsOverriddenTests.cs
@@ -0,0 +1,216 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.Structs.StructWithoutElementaryMethodsOverridden;
+
+namespace VSDiagnostics.Test.Tests.Structs
+{
+ [TestClass]
+ public class StructWithoutElementaryMethodsOverriddenTests : CSharpCodeFixVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new StructWithoutElementaryMethodsOverriddenAnalyzer();
+ protected override CodeFixProvider CodeFixProvider => new StructWithoutElementaryMethodsOverriddenCodeFix();
+
+ [TestMethod]
+ public void StructWithoutElementaryMethodsOverridden_NoMethodsImplemented()
+ {
+ var original = @"
+struct X
+{
+}";
+
+ var result = @"
+struct X
+{
+ public override bool Equals(object obj)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override int GetHashCode()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override string ToString()
+ {
+ throw new System.NotImplementedException();
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(StructWithoutElementaryMethodsOverriddenAnalyzer.Rule.MessageFormat.ToString(), "X"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void StructWithoutElementaryMethodsOverridden_EqualsImplemented()
+ {
+ var original = @"
+struct X
+{
+ public override bool Equals(object obj)
+ {
+ return false;
+ }
+}";
+
+ var result = @"
+struct X
+{
+ public override bool Equals(object obj)
+ {
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override string ToString()
+ {
+ throw new System.NotImplementedException();
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(StructWithoutElementaryMethodsOverriddenAnalyzer.Rule.MessageFormat.ToString(), "X"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void StructWithoutElementaryMethodsOverridden_GetHashCodeImplemented()
+ {
+ var original = @"
+struct X
+{
+ public override int GetHashCode()
+ {
+ return 0;
+ }
+}";
+
+ var result = @"
+struct X
+{
+ public override int GetHashCode()
+ {
+ return 0;
+ }
+
+ public override bool Equals(object obj)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override string ToString()
+ {
+ throw new System.NotImplementedException();
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(StructWithoutElementaryMethodsOverriddenAnalyzer.Rule.MessageFormat.ToString(), "X"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void StructWithoutElementaryMethodsOverridden_ToStringImplemented()
+ {
+ var original = @"
+struct X
+{
+ public override string ToString()
+ {
+ return string.Empty;
+ }
+}";
+
+ var result = @"
+struct X
+{
+ public override string ToString()
+ {
+ return string.Empty;
+ }
+
+ public override bool Equals(object obj)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override int GetHashCode()
+ {
+ throw new System.NotImplementedException();
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(StructWithoutElementaryMethodsOverriddenAnalyzer.Rule.MessageFormat.ToString(), "X"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void StructWithoutElementaryMethodsOverridden_EqualsAndGetHashCodeImplemented()
+ {
+ var original = @"
+struct X
+{
+ public override bool Equals(object obj)
+ {
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return 0;
+ }
+}";
+
+ var result = @"
+struct X
+{
+ public override bool Equals(object obj)
+ {
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return 0;
+ }
+
+ public override string ToString()
+ {
+ throw new System.NotImplementedException();
+ }
+}";
+
+ VerifyDiagnostic(original, string.Format(StructWithoutElementaryMethodsOverriddenAnalyzer.Rule.MessageFormat.ToString(), "X"));
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void StructWithoutElementaryMethodsOverridden_AllImplemented()
+ {
+ var original = @"
+struct X
+{
+ public override bool Equals(object obj)
+ {
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return 0;
+ }
+
+ public override string ToString()
+ {
+ return string.Empty;
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Tests/TestMethodWithoutTestAttributeTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Tests/TestMethodWithoutTestAttributeTests.cs
new file mode 100644
index 0000000..43d89ee
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Tests/TestMethodWithoutTestAttributeTests.cs
@@ -0,0 +1,187 @@
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.Tests.TestMethodWithoutTestAttribute;
+
+namespace VSDiagnostics.Test.Tests.Tests
+{
+ [TestClass]
+ public class TestMethodWithoutTestAttributeTests : CSharpDiagnosticVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new TestMethodWithoutTestAttributeAnalyzer();
+
+ [TestMethod]
+ public void TestMethodWithoutTestAttribute_MSTest()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ [TestClass]
+ class MyClass
+ {
+ public void MyMethod()
+ {
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Method MyMethod might be missing a test attribute");
+ }
+
+ [TestMethod]
+ public void TestMethodWithoutTestAttribute_NUnit()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ [TestFixture]
+ class MyClass
+ {
+ public void MyMethod()
+ {
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Method MyMethod might be missing a test attribute");
+ }
+
+ [TestMethod]
+ public void TestMethodWithoutTestAttribute_XUnit_NoOtherMethodsWithAttribute()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public void MyMethod()
+ {
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void TestMethodWithoutTestAttribute_XUnit_OtherMethodWithAttribute()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public void MyMethod()
+ {
+ }
+
+ [Fact]
+ public void MyOtherMethod()
+ {
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Method MyMethod might be missing a test attribute");
+ }
+
+ [TestMethod]
+ public void TestMethodWithoutTestAttribute_struct()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ [TestClass]
+ struct MyStruct
+ {
+ public void MyMethod()
+ {
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Method MyMethod might be missing a test attribute");
+ }
+
+ [TestMethod]
+ public void TestMethodWithoutTestAttribute_TaskReturn()
+ {
+ var original = @"
+using System.Threading.Tasks;
+
+namespace ConsoleApplication1
+{
+ [TestClass]
+ class MyClass
+ {
+ public async Task MyMethod()
+ {
+ await Task.Delay(0);
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Method MyMethod might be missing a test attribute");
+ }
+
+ [TestMethod]
+ public void TestMethodWithoutTestAttribute_TaskTReturn()
+ {
+ var original = @"
+using System.Threading.Tasks;
+
+namespace ConsoleApplication1
+{
+ [TestClass]
+ class MyClass
+ {
+ public Task MyMethod()
+ {
+ return Task.FromResult(5);
+ }
+ }
+}";
+
+ VerifyDiagnostic(original, "Method MyMethod might be missing a test attribute");
+ }
+
+ [TestMethod]
+ public void TestMethodWithoutTestAttribute_OtherReturnType()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ [TestClass]
+ class MyClass
+ {
+ public int MyMethod()
+ {
+ return 5;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void TestMethodWithoutTestAttribute_OtherAttribute()
+ {
+ var original = @"
+namespace ConsoleApplication1
+{
+ [TestClass]
+ class MyClass
+ {
+ [SomethingElse]
+ public int MyMethod()
+ {
+ return 5;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+ }
+}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Utilities/ExtensionsTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Utilities/ExtensionsTests.cs
index 6466588..d220df5 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Utilities/ExtensionsTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Utilities/ExtensionsTests.cs
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Utilities/NamingConventionsTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Utilities/NamingConventionsTests.cs
index bc40e74..15407c1 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Utilities/NamingConventionsTests.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/Utilities/NamingConventionsTests.cs
@@ -1,7 +1,6 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using VSDiagnostics.Diagnostics.General.NamingConventions;
-using VSDiagnostics.Utilities;
namespace VSDiagnostics.Test.Tests.Utilities
{
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/VSDiagnostics.Test.csproj b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/VSDiagnostics.Test.csproj
index 107bd62..c8e7970 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/VSDiagnostics.Test.csproj
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/VSDiagnostics.Test.csproj
@@ -10,7 +10,7 @@
Properties
VSDiagnostics.Test
VSDiagnostics.Test
- v4.5
+ v4.5.2
512
@@ -63,7 +63,7 @@
True
- ..\..\packages\RoslynTester.1.6.2\lib\RoslynTester.dll
+ ..\..\packages\RoslynTester.1.6.3\lib\RoslynTester.dll
True
@@ -71,24 +71,24 @@
..\..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
True
-
- ..\..\packages\Microsoft.Composition.1.0.30\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll
+
+ ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll
True
-
- ..\..\packages\Microsoft.Composition.1.0.30\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll
+
+ ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll
True
-
- ..\..\packages\Microsoft.Composition.1.0.30\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll
+
+ ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll
True
-
- ..\..\packages\Microsoft.Composition.1.0.30\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll
+
+ ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll
True
-
- ..\..\packages\Microsoft.Composition.1.0.30\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll
+
+ ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll
True
@@ -103,40 +103,47 @@
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
-
-
+
+
+
+
@@ -144,9 +151,11 @@
+
+
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/app.config b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/app.config
index 4d5b6d9..aec9512 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/app.config
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/app.config
@@ -1,35 +1,50 @@
-
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
\ No newline at end of file
+
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/packages.config b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/packages.config
index ef1dae9..2a8bbab 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/packages.config
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/packages.config
@@ -1,15 +1,30 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/VSDiagnostics.Vsix.csproj b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/VSDiagnostics.Vsix.csproj
index f4eea85..516cbed 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/VSDiagnostics.Vsix.csproj
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/VSDiagnostics.Vsix.csproj
@@ -1,8 +1,14 @@
- 14.0
+ 15.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+
+
+ 14.0
@@ -15,7 +21,7 @@
Properties
VSDiagnostics
VSDiagnostics
- v4.5
+ v4.5.2
false
false
false
@@ -47,7 +53,7 @@
/rootsuffix Roslyn
-
+
Designer
@@ -59,67 +65,7 @@
-
- ..\..\packages\Microsoft.CodeAnalysis.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.dll
- True
-
-
- ..\..\packages\Microsoft.CodeAnalysis.CSharp.1.0.0\lib\net45\Microsoft.CodeAnalysis.CSharp.dll
- True
-
-
- ..\..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.0.0\lib\net45\Microsoft.CodeAnalysis.CSharp.Workspaces.dll
- True
-
-
- ..\..\packages\Microsoft.CodeAnalysis.VisualBasic.1.0.0\lib\net45\Microsoft.CodeAnalysis.VisualBasic.dll
- True
-
-
- ..\..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.0.0\lib\net45\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll
- True
-
-
- ..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll
- True
-
-
- ..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll
- True
-
-
- ..\..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
- True
-
-
- ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll
- True
-
-
- ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll
- True
-
-
- ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll
- True
-
-
- ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll
- True
-
-
- ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll
- True
-
-
- ..\..\packages\System.Reflection.Metadata.1.0.21\lib\portable-net45+win8\System.Reflection.Metadata.dll
- True
-
-
-
-
-
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/app.config b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/app.config
new file mode 100644
index 0000000..da592df
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/app.config
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/packages.config b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/packages.config
deleted file mode 100644
index 5eebdf3..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/packages.config
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/source.extension.vsixmanifest b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/source.extension.vsixmanifest
index cf222c6..45733fa 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/source.extension.vsixmanifest
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Vsix/source.extension.vsixmanifest
@@ -2,25 +2,28 @@
-
-
- VSDiagnostics.Vsix
- This is a sample diagnostic extension for the .NET Compiler Platform ("Roslyn").
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ VSDiagnostics.Vsix
+ This is a sample diagnostic extension for the .NET Compiler Platform ("Roslyn").
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostic.nuspec b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostic.nuspec
index 1328224..2e0d656 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostic.nuspec
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostic.nuspec
@@ -2,7 +2,7 @@
VSDiagnostics
- 1.9.3
+ 1.9.4
VSDiagnostics
Jeroen Vannevel
Jeroen Vannevel
@@ -10,7 +10,7 @@
https://github.com/Vannevelj/VSDiagnostics
false
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.
- For the latest releasenotes, see the Github release: https://github.com/Vannevelj/VSDiagnostics/releases/tag/v1.9.3
+ For the latest releasenotes, see the Github release: https://github.com/Vannevelj/VSDiagnostics/releases/tag/v1.9.4
Jeroen Vannevel
Visual Studio, Roslyn, Diagnostics, Analyzers
@@ -18,6 +18,7 @@
+
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Arithmetic/DivideIntegerByInteger/DivideIntegerByIntegerAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Arithmetic/DivideIntegerByInteger/DivideIntegerByIntegerAnalyzer.cs
new file mode 100644
index 0000000..32215a4
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Arithmetic/DivideIntegerByInteger/DivideIntegerByIntegerAnalyzer.cs
@@ -0,0 +1,56 @@
+using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.Arithmetic.DivideIntegerByInteger
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class DivideIntegerByIntegerAnalyzer : DiagnosticAnalyzer
+ {
+ private static readonly SpecialType[] IntegerTypes =
+ {
+ SpecialType.System_Byte, SpecialType.System_Int16, SpecialType.System_Int32, SpecialType.System_Int64,
+ SpecialType.System_SByte, SpecialType.System_UInt16, SpecialType.System_UInt32, SpecialType.System_UInt64
+ };
+
+ private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
+ private static readonly string Category = VSDiagnosticsResources.ArithmeticCategory;
+ private static readonly string Message = VSDiagnosticsResources.DivideIntegerByIntegerAnalyzerMessage;
+ private static readonly string Title = VSDiagnosticsResources.DivideIntegerByIntegerAnalyzerTitle;
+
+ internal static DiagnosticDescriptor Rule =>
+ new DiagnosticDescriptor(DiagnosticId.DivideIntegerByInteger, Title, Message, Category, Severity, isEnabledByDefault: true);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.DivideExpression);
+
+ private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
+ {
+ var divideExpression = (BinaryExpressionSyntax) context.Node;
+ var leftType = context.SemanticModel.GetTypeInfo(divideExpression.Left).Type;
+ if (leftType == null)
+ {
+ return;
+ }
+
+ if (IntegerTypes.Contains(leftType.SpecialType))
+ {
+ var rightType = context.SemanticModel.GetTypeInfo(divideExpression.Right).Type;
+ if (rightType == null)
+ {
+ return;
+ }
+
+ if (IntegerTypes.Contains(rightType.SpecialType))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule, divideExpression.GetLocation(), divideExpression.ToString()));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithVoidReturnType/AsyncMethodWithVoidReturnTypeAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithVoidReturnType/AsyncMethodWithVoidReturnTypeAnalyzer.cs
new file mode 100644
index 0000000..b04fc43
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithVoidReturnType/AsyncMethodWithVoidReturnTypeAnalyzer.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.Async.AsyncMethodWithVoidReturnType
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class AsyncMethodWithVoidReturnTypeAnalyzer : DiagnosticAnalyzer
+ {
+ private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
+
+ private static readonly string Category = VSDiagnosticsResources.AsyncCategory;
+ private static readonly string Message = VSDiagnosticsResources.AsyncMethodWithVoidReturnTypeMessage;
+ private static readonly string Title = VSDiagnosticsResources.AsyncMethodWithVoidReturnTypeTitle;
+
+ internal static DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId.AsyncMethodWithVoidReturnType, Title, Message, Category, Severity, isEnabledByDefault: true);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.MethodDeclaration);
+
+ private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
+ {
+ var method = (MethodDeclarationSyntax) context.Node;
+
+ // Method has to return void
+ var returnType = context.SemanticModel.GetTypeInfo(method.ReturnType);
+ if (returnType.Type == null || returnType.Type.SpecialType != SpecialType.System_Void)
+ {
+ return;
+ }
+
+ var isAsync = false;
+ foreach (var modifier in method.Modifiers)
+ {
+ // Method has to be marked async
+ if (modifier.IsKind(SyntaxKind.AsyncKeyword))
+ {
+ isAsync = true;
+ }
+
+ // Partial methods can only have a void return type
+ if (modifier.IsKind(SyntaxKind.PartialKeyword))
+ {
+ return;
+ }
+ }
+
+ if (!isAsync)
+ {
+ return;
+ }
+
+ // Event handlers can only have a void return type
+ if (method.ParameterList?.Parameters.Count == 2)
+ {
+ var parameters = method.ParameterList.Parameters;
+ var firstArgumentType = context.SemanticModel.GetTypeInfo(parameters[0].Type);
+ var isFirstArgumentObject = firstArgumentType.Type != null &&
+ firstArgumentType.Type.SpecialType == SpecialType.System_Object;
+
+
+ var secondArgumentType = context.SemanticModel.GetTypeInfo(parameters[1].Type);
+ var isSecondArgumentEventArgs = secondArgumentType.Type != null &&
+ secondArgumentType.Type.InheritsFrom(typeof(EventArgs));
+
+ if (isFirstArgumentObject && isSecondArgumentEventArgs)
+ {
+ return;
+ }
+ }
+
+ context.ReportDiagnostic(Diagnostic.Create(Rule, method.GetLocation(), method.Identifier.ValueText));
+ }
+ }
+}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithVoidReturnType/AsyncMethodWithVoidReturnTypeCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithVoidReturnType/AsyncMethodWithVoidReturnTypeCodeFix.cs
new file mode 100644
index 0000000..3af654d
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithVoidReturnType/AsyncMethodWithVoidReturnTypeCodeFix.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Formatting;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.Async.AsyncMethodWithVoidReturnType
+{
+ [ExportCodeFixProvider(DiagnosticId.AsyncMethodWithVoidReturnType + "CF", LanguageNames.CSharp), Shared]
+ public class AsyncMethodWithVoidReturnTypeCodeFix : CodeFixProvider
+ {
+ public override ImmutableArray FixableDiagnosticIds
+ => ImmutableArray.Create(AsyncMethodWithVoidReturnTypeAnalyzer.Rule.Id);
+
+ public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
+
+ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+ var diagnostic = context.Diagnostics.First();
+ var diagnosticSpan = diagnostic.Location.SourceSpan;
+ var methodDeclaration =
+ root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First();
+
+ context.RegisterCodeFix(
+ CodeAction.Create(VSDiagnosticsResources.AsyncMethodWithVoidReturnTypeCodeFixTitle,
+ x => ChangeReturnTypeAsync(context.Document, methodDeclaration, root, x),
+ AsyncMethodWithVoidReturnTypeAnalyzer.Rule.Id),
+ diagnostic);
+ }
+
+ private Task ChangeReturnTypeAsync(Document document, MethodDeclarationSyntax methodDeclaration, SyntaxNode root, CancellationToken cancellationToken)
+ {
+ var newMethod = methodDeclaration.WithReturnType(SyntaxFactory.ParseTypeName("Task").WithAdditionalAnnotations(Formatter.Annotation));
+ var newRoot = root.ReplaceNode(methodDeclaration, newMethod);
+ var newDocument = document.WithSyntaxRoot(newRoot);
+
+ return Task.FromResult(newDocument);
+ }
+ }
+}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithoutAsyncSuffix/AsyncMethodWithoutAsyncSuffixAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithoutAsyncSuffix/AsyncMethodWithoutAsyncSuffixAnalyzer.cs
index 0b0a36a..77ec6de 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithoutAsyncSuffix/AsyncMethodWithoutAsyncSuffixAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithoutAsyncSuffix/AsyncMethodWithoutAsyncSuffixAnalyzer.cs
@@ -1,5 +1,4 @@
using System.Collections.Immutable;
-using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -24,18 +23,11 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.MethodDeclaration);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.MethodDeclaration);
private static void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
{
- var method = context.Node as MethodDeclarationSyntax;
- if (method == null)
- {
- return;
- }
+ var method = (MethodDeclarationSyntax) context.Node;
if (method.Modifiers.Any(SyntaxKind.OverrideKeyword))
{
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithoutAsyncSuffix/AsyncMethodWithoutAsyncSuffixCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithoutAsyncSuffix/AsyncMethodWithoutAsyncSuffixCodeFix.cs
index 8a0df97..9540336 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithoutAsyncSuffix/AsyncMethodWithoutAsyncSuffixCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/AsyncMethodWithoutAsyncSuffix/AsyncMethodWithoutAsyncSuffixCodeFix.cs
@@ -11,7 +11,7 @@
namespace VSDiagnostics.Diagnostics.Async.AsyncMethodWithoutAsyncSuffix
{
- [ExportCodeFixProvider(nameof(AsyncMethodWithoutAsyncSuffixCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.AsyncMethodWithoutAsyncSuffix + "CF", LanguageNames.CSharp), Shared]
public class AsyncMethodWithoutAsyncSuffixCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds
@@ -29,15 +29,13 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
context.RegisterCodeFix(
CodeAction.Create(VSDiagnosticsResources.AsyncMethodWithoutAsyncSuffixCodeFixTitle,
- x => AddSuffixAsync(context.Document, methodDeclaration, root, context.CancellationToken),
+ x => AddSuffixAsync(context.Document, methodDeclaration, root, x),
AsyncMethodWithoutAsyncSuffixAnalyzer.Rule.Id),
diagnostic);
}
private async Task AddSuffixAsync(Document document, MethodDeclarationSyntax methodDeclaration, SyntaxNode root,
- CancellationToken cancellationToken)
- {
- return await RenameHelper.RenameSymbolAsync(document, root, methodDeclaration.Identifier, methodDeclaration.Identifier.Text + "Async", cancellationToken);
- }
+ CancellationToken cancellationToken)
+ => await RenameHelper.RenameSymbolAsync(document, root, methodDeclaration.Identifier, methodDeclaration.Identifier.Text + "Async", cancellationToken);
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/SyncMethodWithAsyncSuffix/SyncMethodWithAsyncSuffixAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/SyncMethodWithAsyncSuffix/SyncMethodWithAsyncSuffixAnalyzer.cs
index e7fdbad..79c1a98 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/SyncMethodWithAsyncSuffix/SyncMethodWithAsyncSuffixAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/SyncMethodWithAsyncSuffix/SyncMethodWithAsyncSuffixAnalyzer.cs
@@ -1,12 +1,11 @@
using System.Collections.Immutable;
-using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using VSDiagnostics.Utilities;
-namespace VSDiagnostics.Diagnostics.Async.SyncMethodWithSyncSuffix
+namespace VSDiagnostics.Diagnostics.Async.SyncMethodWithAsyncSuffix
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class SyncMethodWithAsyncSuffixAnalyzer : DiagnosticAnalyzer
@@ -14,28 +13,19 @@ public class SyncMethodWithAsyncSuffixAnalyzer : DiagnosticAnalyzer
private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
private static readonly string Category = VSDiagnosticsResources.AsyncCategory;
- private static readonly string Message = VSDiagnosticsResources.SyncMethodWithSyncSuffixAnalyzerMessage;
- private static readonly string Title = VSDiagnosticsResources.SyncMethodWithSyncSuffixAnalyzerTitle;
+ private static readonly string Message = VSDiagnosticsResources.SyncMethodWithAsyncSuffixAnalyzerMessage;
+ private static readonly string Title = VSDiagnosticsResources.SyncMethodWithAsyncSuffixAnalyzerTitle;
internal static DiagnosticDescriptor Rule
- =>
- new DiagnosticDescriptor(DiagnosticId.SyncMethodWithAsyncSuffix, Title, Message, Category, Severity,
- isEnabledByDefault: true);
+ => new DiagnosticDescriptor(DiagnosticId.SyncMethodWithAsyncSuffix, Title, Message, Category, Severity, true);
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.MethodDeclaration);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.MethodDeclaration);
private static void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
{
- var method = context.Node as MethodDeclarationSyntax;
- if (method == null)
- {
- return;
- }
+ var method = (MethodDeclarationSyntax) context.Node;
if (method.Modifiers.Any(SyntaxKind.OverrideKeyword))
{
@@ -62,7 +52,7 @@ private static void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
if (!declaredSymbol.IsAsync() && method.Identifier.Text.EndsWith("Async"))
{
context.ReportDiagnostic(Diagnostic.Create(Rule, method.Identifier.GetLocation(),
- method.Identifier.Text));
+ method.Identifier.Text));
}
}
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/SyncMethodWithAsyncSuffix/SyncMethodWithAsyncSuffixCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/SyncMethodWithAsyncSuffix/SyncMethodWithAsyncSuffixCodeFix.cs
index c5c5041..3970fca 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/SyncMethodWithAsyncSuffix/SyncMethodWithAsyncSuffixCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Async/SyncMethodWithAsyncSuffix/SyncMethodWithAsyncSuffixCodeFix.cs
@@ -9,10 +9,9 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using VSDiagnostics.Utilities;
-namespace VSDiagnostics.Diagnostics.Async.SyncMethodWithSyncSuffix
+namespace VSDiagnostics.Diagnostics.Async.SyncMethodWithAsyncSuffix
{
-
- [ExportCodeFixProvider(nameof(SyncMethodWithAsyncSuffixCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.SyncMethodWithAsyncSuffix + "CF", LanguageNames.CSharp), Shared]
public class SyncMethodWithAsyncSuffixCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds
@@ -27,14 +26,14 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First();
context.RegisterCodeFix(
- CodeAction.Create(VSDiagnosticsResources.SyncMethodWithSyncSuffixAnalyzerCodeFixTitle,
- x => RemoveSuffixAsync(context.Document, methodDeclaration, root, context.CancellationToken),
+ CodeAction.Create(VSDiagnosticsResources.SyncMethodWithAsyncSuffixAnalyzerCodeFixTitle,
+ x => RemoveSuffixAsync(context.Document, methodDeclaration, root, x),
SyncMethodWithAsyncSuffixAnalyzer.Rule.Id),
diagnostic);
}
private async Task RemoveSuffixAsync(Document document, MethodDeclarationSyntax methodDeclaration, SyntaxNode root,
- CancellationToken cancellationToken)
+ CancellationToken cancellationToken)
{
var origMethodName = methodDeclaration.Identifier.Text;
var newMethodName = origMethodName.Substring(0, origMethodName.Length - "Async".Length);
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/AttributeWithEmptyArgumentList/AttributeWithEmptyArgumentListAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/AttributeWithEmptyArgumentList/AttributeWithEmptyArgumentListAnalyzer.cs
index 46bca99..7a1fd2f 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/AttributeWithEmptyArgumentList/AttributeWithEmptyArgumentListAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/AttributeWithEmptyArgumentList/AttributeWithEmptyArgumentListAnalyzer.cs
@@ -1,15 +1,13 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using VSDiagnostics.Utilities;
-using CSharpSyntaxKind = Microsoft.CodeAnalysis.CSharp.SyntaxKind;
-using VisualBasicSyntaxKind = Microsoft.CodeAnalysis.VisualBasic.SyntaxKind;
-using CSharpAttributeSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.AttributeSyntax;
-using VisualBasicAttributeSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.AttributeSyntax;
namespace VSDiagnostics.Diagnostics.Attributes.AttributeWithEmptyArgumentList
{
- [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
public class AttributeWithEmptyArgumentListAnalyzer : DiagnosticAnalyzer
{
private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
@@ -25,40 +23,23 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeCSharpSymbol, CSharpSyntaxKind.Attribute);
- context.RegisterSyntaxNodeAction(AnalyzeVisualBasicSymbol, VisualBasicSyntaxKind.Attribute);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeCSharpSymbol, SyntaxKind.Attribute);
private void AnalyzeCSharpSymbol(SyntaxNodeAnalysisContext context)
{
- var attributeExpression = context.Node as CSharpAttributeSyntax;
+ var attributeSyntax = (AttributeSyntax) context.Node;
// attribute must have arguments
// if there are no parenthesis, the ArgumentList is null
// if there are empty parenthesis, the ArgumentList is empty
- if (attributeExpression?.ArgumentList == null || attributeExpression.ArgumentList.Arguments.Any())
+ if (attributeSyntax.ArgumentList == null || attributeSyntax.ArgumentList.Arguments.Any())
{
return;
}
- context.ReportDiagnostic(Diagnostic.Create(Rule, attributeExpression.GetLocation()));
- }
-
- private void AnalyzeVisualBasicSymbol(SyntaxNodeAnalysisContext context)
- {
- var attributeExpression = context.Node as VisualBasicAttributeSyntax;
-
- // attribute must have arguments
- // if there are no parenthesis, the ArgumentList is null
- // if there are empty parenthesis, the ArgumentList is empty
- if (attributeExpression?.ArgumentList == null || attributeExpression.ArgumentList.Arguments.Any())
- {
- return;
- }
+ var attributeName = attributeSyntax.Name.ToString();
- context.ReportDiagnostic(Diagnostic.Create(Rule, attributeExpression.GetLocation()));
+ context.ReportDiagnostic(Diagnostic.Create(Rule, attributeSyntax.GetLocation(), attributeName));
}
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/AttributeWithEmptyArgumentList/AttributeWithEmptyArgumentListCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/AttributeWithEmptyArgumentList/AttributeWithEmptyArgumentListCodeFix.cs
index 3eaa71f..4c2224f 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/AttributeWithEmptyArgumentList/AttributeWithEmptyArgumentListCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/AttributeWithEmptyArgumentList/AttributeWithEmptyArgumentListCodeFix.cs
@@ -5,13 +5,12 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
-using CSharpAttributeSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.AttributeSyntax;
-using VisualBasicAttributeSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.AttributeSyntax;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.Attributes.AttributeWithEmptyArgumentList
{
- [ExportCodeFixProvider(nameof(AttributeWithEmptyArgumentListCodeFix), LanguageNames.CSharp,
- LanguageNames.VisualBasic), Shared]
+ [ExportCodeFixProvider(DiagnosticId.AttributeWithEmptyArgumentList + "CF", LanguageNames.CSharp), Shared]
public class AttributeWithEmptyArgumentListCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds
@@ -34,30 +33,9 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
private Task RemoveEmptyArgumentListAsync(Document document, SyntaxNode root, SyntaxNode statement)
{
- SyntaxNode newRoot = null;
-
- if (statement is CSharpAttributeSyntax)
- {
- newRoot = RemoveEmptyArgumentListCSharp(root, (CSharpAttributeSyntax) statement);
- }
- else if (statement is VisualBasicAttributeSyntax)
- {
- newRoot = RemoveEmptyArgumentListVisualBasic(root, (VisualBasicAttributeSyntax) statement);
- }
-
+ var newRoot = root.RemoveNode(((AttributeSyntax) statement).ArgumentList, SyntaxRemoveOptions.KeepNoTrivia);
var newDocument = document.WithSyntaxRoot(newRoot);
return Task.FromResult(newDocument.Project.Solution);
}
-
- private SyntaxNode RemoveEmptyArgumentListCSharp(SyntaxNode root, CSharpAttributeSyntax attributeExpression)
- {
- return root.RemoveNode(attributeExpression.ArgumentList, SyntaxRemoveOptions.KeepNoTrivia);
- }
-
- private SyntaxNode RemoveEmptyArgumentListVisualBasic(SyntaxNode root,
- VisualBasicAttributeSyntax attributeExpression)
- {
- return root.RemoveNode(attributeExpression.ArgumentList, SyntaxRemoveOptions.KeepNoTrivia);
- }
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/EnumCanHaveFlagsAttribute/EnumCanHaveFlagsAttributeAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/EnumCanHaveFlagsAttribute/EnumCanHaveFlagsAttributeAnalyzer.cs
index 5529940..2d7c208 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/EnumCanHaveFlagsAttribute/EnumCanHaveFlagsAttributeAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/EnumCanHaveFlagsAttribute/EnumCanHaveFlagsAttributeAnalyzer.cs
@@ -1,17 +1,14 @@
using System;
using System.Collections.Immutable;
-using System.Linq;
using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.VisualBasic.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
using VSDiagnostics.Utilities;
-using CSharpSyntaxKind = Microsoft.CodeAnalysis.CSharp.SyntaxKind;
-using VisualBasicSyntaxKind = Microsoft.CodeAnalysis.VisualBasic.SyntaxKind;
namespace VSDiagnostics.Diagnostics.Attributes.EnumCanHaveFlagsAttribute
{
- [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
public class EnumCanHaveFlagsAttributeAnalyzer : DiagnosticAnalyzer
{
private const DiagnosticSeverity Severity = DiagnosticSeverity.Hidden;
@@ -25,47 +22,22 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeCSharpSymbol, CSharpSyntaxKind.EnumDeclaration);
- context.RegisterSyntaxNodeAction(AnalyzeVisualBasicSymbol, VisualBasicSyntaxKind.EnumStatement);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.EnumDeclaration);
- private void AnalyzeCSharpSymbol(SyntaxNodeAnalysisContext context)
+ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
var enumDeclaration = (EnumDeclarationSyntax) context.Node;
- // enum must not already have flags attribute
- if (enumDeclaration.AttributeLists.Any(
- a => a.Attributes.Any(
- t =>
- {
- var symbol = context.SemanticModel.GetSymbolInfo(t).Symbol;
-
- return symbol == null || symbol.ContainingType.MetadataName == typeof (FlagsAttribute).Name;
- })))
+ foreach (var list in enumDeclaration.AttributeLists)
{
- return;
- }
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, enumDeclaration.GetLocation()));
- }
-
- private void AnalyzeVisualBasicSymbol(SyntaxNodeAnalysisContext context)
- {
- var enumDeclaration = (EnumStatementSyntax) context.Node;
-
- // enum must not already have flags attribute
- if (enumDeclaration.AttributeLists.Any(
- a => a.Attributes.Any(
- t =>
+ foreach (var attribute in list.Attributes)
+ {
+ var symbol = context.SemanticModel.GetSymbolInfo(attribute).Symbol;
+ if (symbol == null || symbol.ContainingType.MetadataName == typeof (FlagsAttribute).Name)
{
- var symbol = context.SemanticModel.GetSymbolInfo(t).Symbol;
-
- return symbol == null || symbol.ContainingType.MetadataName == typeof (FlagsAttribute).Name;
- })))
- {
- return;
+ return;
+ }
+ }
}
context.ReportDiagnostic(Diagnostic.Create(Rule, enumDeclaration.GetLocation()));
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/EnumCanHaveFlagsAttribute/EnumCanHaveFlagsAttributeCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/EnumCanHaveFlagsAttribute/EnumCanHaveFlagsAttributeCodeFix.cs
index f4c1c2e..48b4d30 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/EnumCanHaveFlagsAttribute/EnumCanHaveFlagsAttributeCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/EnumCanHaveFlagsAttribute/EnumCanHaveFlagsAttributeCodeFix.cs
@@ -1,24 +1,18 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
+using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
-using Microsoft.CodeAnalysis.Formatting;
-using Microsoft.CodeAnalysis.VisualBasic.Syntax;
-using CSharpCompilationUnitSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax;
-using VisualBasicCompilationUnitSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.CompilationUnitSyntax;
-using CSharpSyntaxFactory = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
-using VisualBasicSyntaxFactory = Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.Attributes.EnumCanHaveFlagsAttribute
{
- [ExportCodeFixProvider(nameof(EnumCanHaveFlagsAttributeCodeFix), LanguageNames.CSharp, LanguageNames.VisualBasic),
+ [ExportCodeFixProvider(DiagnosticId.EnumCanHaveFlagsAttribute + "CF", LanguageNames.CSharp),
Shared]
public class EnumCanHaveFlagsAttributeCodeFix : CodeFixProvider
{
@@ -41,34 +35,17 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
}
private Task AddFlagAttributeAsync(Document document, SyntaxNode root, SyntaxNode statement)
- {
- SyntaxNode newRoot = null;
-
- if (statement is EnumDeclarationSyntax)
- {
- newRoot = AddFlagAttributeCSharp(document, root, (EnumDeclarationSyntax) statement);
- }
- else if (statement is EnumStatementSyntax)
- {
- newRoot = AddFlagAttributeVisualBasic(document, root, (EnumStatementSyntax) statement);
- }
-
- var newDocument = document.WithSyntaxRoot(newRoot);
- return Task.FromResult(newDocument.Project.Solution);
- }
-
- private SyntaxNode AddFlagAttributeCSharp(Document document, SyntaxNode root, SyntaxNode statement)
{
var generator = SyntaxGenerator.GetGenerator(document);
- var flagsAttribute = CSharpSyntaxFactory.Attribute(CSharpSyntaxFactory.ParseName("Flags"));
+ var flagsAttribute = SyntaxFactory.Attribute(SyntaxFactory.ParseName("Flags"));
var newStatement = generator.AddAttributes(statement, flagsAttribute);
var newRoot = root.ReplaceNode(statement, newStatement);
- var compilationUnit = (CSharpCompilationUnitSyntax) newRoot;
+ var compilationUnit = (CompilationUnitSyntax) newRoot;
- var usingSystemDirective = CSharpSyntaxFactory.UsingDirective(CSharpSyntaxFactory.ParseName("System"));
+ var usingSystemDirective = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("System"));
var usingDirectives = compilationUnit.Usings.Select(u => u.Name.GetText().ToString());
if (usingDirectives.All(u => u != usingSystemDirective.Name.GetText().ToString()))
@@ -76,39 +53,8 @@ private SyntaxNode AddFlagAttributeCSharp(Document document, SyntaxNode root, Sy
newRoot = generator.AddNamespaceImports(compilationUnit, usingSystemDirective);
}
- return newRoot;
- }
-
- private SyntaxNode AddFlagAttributeVisualBasic(Document document, SyntaxNode root, SyntaxNode statement)
- {
- var generator = SyntaxGenerator.GetGenerator(document);
-
- var flagsAttribute = VisualBasicSyntaxFactory.Attribute(VisualBasicSyntaxFactory.ParseName("Flags"));
- var newStatement = generator.AddAttributes(statement, flagsAttribute);
-
- var newRoot = root.ReplaceNode(statement, newStatement).WithAdditionalAnnotations(Formatter.Annotation);
-
- var compilationUnit = (VisualBasicCompilationUnitSyntax) newRoot;
-
- var importSystemClause =
- VisualBasicSyntaxFactory.SimpleImportsClause(
- VisualBasicSyntaxFactory.ParseName("System"))
- .WithTrailingTrivia(
- VisualBasicSyntaxFactory.SyntaxTrivia(
- Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.EndOfLineTrivia, Environment.NewLine));
- var importsList = VisualBasicSyntaxFactory.SeparatedList(new List {importSystemClause});
- var importStatement = VisualBasicSyntaxFactory.ImportsStatement(importsList);
-
- var imports =
- compilationUnit.Imports.SelectMany(
- c => c.ImportsClauses.OfType().Select(i => i.Name.GetText().ToString()));
-
- if (imports.All(u => u != importSystemClause.Name.GetText().ToString()))
- {
- newRoot = generator.AddNamespaceImports(compilationUnit, importStatement);
- }
-
- return newRoot;
+ var newDocument = document.WithSyntaxRoot(newRoot);
+ return Task.FromResult(newDocument.Project.Solution);
}
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/FlagsEnumValuesAreNotPowersOfTwo/FlagsEnumValuesAreNotPowersOfTwoAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/FlagsEnumValuesAreNotPowersOfTwo/FlagsEnumValuesAreNotPowersOfTwoAnalyzer.cs
index 191c029..a075c26 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/FlagsEnumValuesAreNotPowersOfTwo/FlagsEnumValuesAreNotPowersOfTwoAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/FlagsEnumValuesAreNotPowersOfTwo/FlagsEnumValuesAreNotPowersOfTwoAnalyzer.cs
@@ -46,22 +46,31 @@ internal static DiagnosticDescriptor ValuesDontFitRule
public override ImmutableArray SupportedDiagnostics
=> ImmutableArray.Create(DefaultRule, ValuesDontFitRule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.EnumDeclaration);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.EnumDeclaration);
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
var declarationExpression = (EnumDeclarationSyntax) context.Node;
- var flagsAttribute = declarationExpression.AttributeLists.FirstOrDefault(
- a => a.Attributes.FirstOrDefault(
- t =>
+
+ AttributeListSyntax flagsAttribute = null;
+
+ foreach (var list in declarationExpression.AttributeLists)
+ {
+ foreach (var attribute in list.Attributes)
+ {
+ var symbol = context.SemanticModel.GetSymbolInfo(attribute).Symbol;
+ if (symbol == null || symbol.ContainingType.MetadataName == typeof (FlagsAttribute).Name)
{
- var symbol = context.SemanticModel.GetSymbolInfo(t).Symbol;
- return symbol == null || symbol.ContainingType.MetadataName == typeof(FlagsAttribute).Name;
- }) != null);
+ flagsAttribute = list;
+ break;
+ }
+ }
+ if (flagsAttribute != null)
+ {
+ break;
+ }
+ }
if (flagsAttribute == null)
{
@@ -70,7 +79,7 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
var enumName = context.SemanticModel.GetDeclaredSymbol(declarationExpression).Name;
var enumMemberDeclarations =
- declarationExpression.ChildNodes().OfType().ToList();
+ declarationExpression.ChildNodes().OfType(SyntaxKind.EnumMemberDeclaration).ToArray();
foreach (var member in enumMemberDeclarations)
{
@@ -79,11 +88,26 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
continue;
}
- var descendantNodes = member.EqualsValue.Value.DescendantNodesAndSelf().ToList();
- if (descendantNodes.OfType().Any() &&
- descendantNodes.OfType().Any())
+ var descendantNodes = member.EqualsValue.Value.DescendantNodesAndSelf();
+
+ var containsLiteralExpression = false;
+ var containsIdentifierName = false;
+ foreach (var node in descendantNodes)
{
- return;
+ if (node is LiteralExpressionSyntax)
+ {
+ containsLiteralExpression = true;
+ }
+
+ if (node.IsKind(SyntaxKind.IdentifierName))
+ {
+ containsIdentifierName = true;
+ }
+
+ if (containsIdentifierName && containsLiteralExpression)
+ {
+ return;
+ }
}
}
@@ -109,7 +133,7 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
// We have to make sure that by moving to powers of two, we won't exceed the type's maximum value
// For example: 255 is the last possible value for a byte enum
- if (IsOutsideOfRange(keyword, enumMemberDeclarations.Count))
+ if (IsOutsideOfRange(keyword, enumMemberDeclarations.Length))
{
context.ReportDiagnostic(Diagnostic.Create(ValuesDontFitRule,
declarationExpression.Identifier.GetLocation(),
@@ -129,9 +153,19 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
if (member.EqualsValue.Value is BinaryExpressionSyntax)
{
- var descendantNodes = member.EqualsValue.Value.DescendantNodesAndSelf().ToList();
- if (descendantNodes.Any() &&
- descendantNodes.All(n => n is IdentifierNameSyntax || n is BinaryExpressionSyntax))
+ var descendantNodes = new List(member.EqualsValue.Value.DescendantNodesAndSelf());
+
+ var all = true;
+ foreach (var node in descendantNodes)
+ {
+ if (!node.IsKind(SyntaxKind.IdentifierName) && !(node is BinaryExpressionSyntax))
+ {
+ all = false;
+ break;
+ }
+ }
+
+ if (descendantNodes.Any() && all)
{
continue;
}
@@ -140,7 +174,10 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
var symbol = context.SemanticModel.GetDeclaredSymbol(member);
var value = symbol.ConstantValue;
- if (value == null) { return; }
+ if (value == null)
+ {
+ return;
+ }
/* `value` is an `object`. Casting it to `dynamic`
* will allow us to avoid a huge `switch` statement
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/FlagsEnumValuesAreNotPowersOfTwo/FlagsEnumValuesAreNotPowersOfTwoCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/FlagsEnumValuesAreNotPowersOfTwo/FlagsEnumValuesAreNotPowersOfTwoCodeFix.cs
index abdee77..80b0306 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/FlagsEnumValuesAreNotPowersOfTwo/FlagsEnumValuesAreNotPowersOfTwoCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/FlagsEnumValuesAreNotPowersOfTwo/FlagsEnumValuesAreNotPowersOfTwoCodeFix.cs
@@ -9,10 +9,11 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.Attributes.FlagsEnumValuesAreNotPowersOfTwo
{
- [ExportCodeFixProvider(nameof(FlagsEnumValuesAreNotPowersOfTwoCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.FlagsEnumValuesAreNotPowersOfTwo + "CF", LanguageNames.CSharp), Shared]
public class FlagsEnumValuesAreNotPowersOfTwoCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds
@@ -30,11 +31,11 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
context.RegisterCodeFix(
CodeAction.Create(VSDiagnosticsResources.FlagsEnumValuesAreNotPowersOfTwoCodeFixTitle,
- x => AdjustEnumValues(context.Document, root, statement),
+ x => AdjustEnumValuesAsync(context.Document, root, statement),
FlagsEnumValuesAreNotPowersOfTwoAnalyzer.DefaultRule.Id), diagnostic);
}
- private async Task AdjustEnumValues(Document document, SyntaxNode root, SyntaxNode statement)
+ private async Task AdjustEnumValuesAsync(Document document, SyntaxNode root, SyntaxNode statement)
{
var semanticModel = await document.GetSemanticModelAsync();
@@ -112,7 +113,7 @@ private async Task AdjustEnumValues(Document document, SyntaxNode root
var newStatement =
declarationExpression.WithMembers(SyntaxFactory.SeparatedList(enumMemberDeclarations))
- .WithAdditionalAnnotations(Formatter.Annotation);
+ .WithAdditionalAnnotations(Formatter.Annotation);
var newRoot = root.ReplaceNode(statement, newStatement);
return document.WithSyntaxRoot(newRoot).Project.Solution;
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/ObsoleteAttributeWithoutReason/ObsoleteAttributeWithoutReasonAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/ObsoleteAttributeWithoutReason/ObsoleteAttributeWithoutReasonAnalyzer.cs
index c970de9..52ea837 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/ObsoleteAttributeWithoutReason/ObsoleteAttributeWithoutReasonAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/ObsoleteAttributeWithoutReason/ObsoleteAttributeWithoutReasonAnalyzer.cs
@@ -1,16 +1,14 @@
using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using VSDiagnostics.Utilities;
-using CSharpSyntaxKind = Microsoft.CodeAnalysis.CSharp.SyntaxKind;
-using VisualBasicSyntaxKind = Microsoft.CodeAnalysis.VisualBasic.SyntaxKind;
-using CSharpAttributeSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.AttributeSyntax;
-using VisualBasicAttributeSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.AttributeSyntax;
namespace VSDiagnostics.Diagnostics.Attributes.ObsoleteAttributeWithoutReason
{
- [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
public class ObsoleteAttributeWithoutReasonAnalyzer : DiagnosticAnalyzer
{
private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
@@ -24,49 +22,15 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeCSharpSymbol, CSharpSyntaxKind.Attribute);
- context.RegisterSyntaxNodeAction(AnalyzeVisualBasicSymbol, VisualBasicSyntaxKind.Attribute);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeCSharpSymbol, SyntaxKind.Attribute);
private void AnalyzeCSharpSymbol(SyntaxNodeAnalysisContext context)
{
- var attributeExpression = context.Node as CSharpAttributeSyntax;
- if (attributeExpression == null)
- {
- return;
- }
-
- // attribute type must be of type ObsoleteAttribute
- var type = context.SemanticModel.GetSymbolInfo(attributeExpression).Symbol;
- if (type == null || type.ContainingType.MetadataName != typeof (ObsoleteAttribute).Name)
- {
- return;
- }
-
- // attribute must have arguments
- // if there are no parenthesis, the ArgumentList is null
- // if there are empty parenthesis, the ArgumentList is empty
- if (attributeExpression.ArgumentList != null && attributeExpression.ArgumentList.Arguments.Any())
- {
- return;
- }
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, attributeExpression.GetLocation()));
- }
-
- private void AnalyzeVisualBasicSymbol(SyntaxNodeAnalysisContext context)
- {
- var attributeExpression = context.Node as VisualBasicAttributeSyntax;
- if (attributeExpression == null)
- {
- return;
- }
+ var attributeExpression = (AttributeSyntax) context.Node;
// attribute type must be of type ObsoleteAttribute
var type = context.SemanticModel.GetSymbolInfo(attributeExpression).Symbol;
- if (type == null || type.ContainingType.MetadataName != typeof (ObsoleteAttribute).Name)
+ if (type == null || type.ContainingType.MetadataName != typeof(ObsoleteAttribute).Name)
{
return;
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/OnPropertyChangedWithoutCallerMemberName/OnPropertyChangedWithoutCallerMemberNameAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/OnPropertyChangedWithoutCallerMemberName/OnPropertyChangedWithoutCallerMemberNameAnalyzer.cs
index 9c667d6..a0586f5 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/OnPropertyChangedWithoutCallerMemberName/OnPropertyChangedWithoutCallerMemberNameAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/OnPropertyChangedWithoutCallerMemberName/OnPropertyChangedWithoutCallerMemberNameAnalyzer.cs
@@ -1,6 +1,5 @@
using System.Collections.Immutable;
using System.ComponentModel;
-using System.Linq;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
@@ -28,19 +27,21 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.MethodDeclaration);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.MethodDeclaration);
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
- var methodDeclaration = (MethodDeclarationSyntax) context.Node;
- var parentClass = methodDeclaration.Ancestors().OfType().FirstOrDefault();
+ var methodDeclaration = (MethodDeclarationSyntax)context.Node;
+ var parentNode = methodDeclaration.GetEnclosingTypeNode();
+ if (!parentNode.IsKind(SyntaxKind.StructDeclaration) && !parentNode.IsKind(SyntaxKind.ClassDeclaration))
+ {
+ return;
+ }
+ var typeSymbol = (INamedTypeSymbol)context.SemanticModel.GetDeclaredSymbol(parentNode);
// class must implement INotifyPropertyChanged
- if (!parentClass.ImplementsInterface(context.SemanticModel, typeof (INotifyPropertyChanged)))
+ if (!typeSymbol.ImplementsInterfaceOrBaseClass(typeof(INotifyPropertyChanged)))
{
return;
}
@@ -68,13 +69,17 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
}
// parameter must not have CallerMemberNameAttribute
- if (param.AttributeLists.Any(a => a.Attributes.Any() && a.Attributes.Any(t =>
- {
- var symbol = context.SemanticModel.GetSymbolInfo(t).Symbol;
- return symbol != null && symbol.ContainingSymbol.MetadataName == typeof (CallerMemberNameAttribute).Name;
- })))
+ foreach (var list in param.AttributeLists)
{
- return;
+ foreach (var attribute in list.Attributes)
+ {
+ var symbol = context.SemanticModel.GetSymbolInfo(attribute).Symbol;
+ if (symbol != null &&
+ symbol.ContainingSymbol.MetadataName == typeof (CallerMemberNameAttribute).Name)
+ {
+ return;
+ }
+ }
}
context.ReportDiagnostic(Diagnostic.Create(Rule, methodDeclaration.GetLocation()));
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/OnPropertyChangedWithoutCallerMemberName/OnPropertyChangedWithoutCallerMemberNameCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/OnPropertyChangedWithoutCallerMemberName/OnPropertyChangedWithoutCallerMemberNameCodeFix.cs
index 004b4bd..dfe434a 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/OnPropertyChangedWithoutCallerMemberName/OnPropertyChangedWithoutCallerMemberNameCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Attributes/OnPropertyChangedWithoutCallerMemberName/OnPropertyChangedWithoutCallerMemberNameCodeFix.cs
@@ -9,10 +9,11 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.Attributes.OnPropertyChangedWithoutCallerMemberName
{
- [ExportCodeFixProvider(nameof(OnPropertyChangedWithoutCallerMemberNameCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.OnPropertyChangedWithoutCallerMemberName + "CF", LanguageNames.CSharp), Shared]
public class OnPropertyChangedWithoutCallerMemberNameCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds
@@ -29,11 +30,11 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
var statement = root.FindNode(diagnosticSpan);
context.RegisterCodeFix(
CodeAction.Create(VSDiagnosticsResources.OnPropertyChangedWithoutCallerMemberNameCodeFixTitle,
- x => AddCallerMemberNameAttribute(context.Document, statement),
+ x => AddCallerMemberNameAttributeAsync(context.Document, statement),
OnPropertyChangedWithoutCallerMemberNameAnalyzer.Rule.Id), diagnostic);
}
- private async Task AddCallerMemberNameAttribute(Document document, SyntaxNode statement)
+ private async Task AddCallerMemberNameAttributeAsync(Document document, SyntaxNode statement)
{
var editor = await DocumentEditor.CreateAsync(document);
@@ -45,20 +46,20 @@ private async Task AddCallerMemberNameAttribute(Document document, Syn
var newParam = param.Default == null
? param.WithAttributeLists(param.AttributeLists.Add(attributeList))
- .WithDefault(SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression("\"\"")))
+ .WithDefault(SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression("\"\"")))
: param.WithAttributeLists(param.AttributeLists.Add(attributeList));
editor.ReplaceNode(param, newParam);
- var parentClass = methodDeclaration.Ancestors().OfType().FirstOrDefault();
+ var parentNode = methodDeclaration.GetEnclosingTypeNode();
var methodInvocations =
- parentClass.DescendantNodes()
- .OfType().Where(i =>
- {
- var identifierExpression = i.Expression as IdentifierNameSyntax;
- return identifierExpression != null &&
- identifierExpression.Identifier.ValueText == "OnPropertyChanged";
- });
+ parentNode.DescendantNodes()
+ .OfType().Where(i =>
+ {
+ var identifierExpression = i.Expression as IdentifierNameSyntax;
+ return identifierExpression != null &&
+ identifierExpression.Identifier.ValueText == "OnPropertyChanged";
+ });
foreach (var methodInvocation in methodInvocations)
{
@@ -78,10 +79,10 @@ private async Task AddCallerMemberNameAttribute(Document document, Syn
{
var usings =
compilationUnit.Usings.Add(usingSystemRuntimeCompilerServicesDirective)
- .OrderBy(u => u.Name.GetText().ToString());
+ .OrderBy(u => u.Name.GetText().ToString());
newRoot = newRoot.ReplaceNode(compilationUnit, compilationUnit.WithUsings(SyntaxFactory.List(usings))
- .WithAdditionalAnnotations(Formatter.Annotation));
+ .WithAdditionalAnnotations(Formatter.Annotation));
}
var newDocument = document.WithSyntaxRoot(newRoot);
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ArgumentExceptionWithoutNameofOperator/ArgumentExceptionWithoutNameofOperatorAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ArgumentExceptionWithoutNameofOperator/ArgumentExceptionWithoutNameofOperatorAnalyzer.cs
index 766cc6c..19bc724 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ArgumentExceptionWithoutNameofOperator/ArgumentExceptionWithoutNameofOperatorAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ArgumentExceptionWithoutNameofOperator/ArgumentExceptionWithoutNameofOperatorAnalyzer.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
@@ -27,51 +28,83 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.ObjectCreationExpression);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.ObjectCreationExpression);
private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
{
- var objectCreationExpression = context.Node as ObjectCreationExpressionSyntax;
- if (objectCreationExpression?.ArgumentList == null || !objectCreationExpression.ArgumentList.Arguments.Any())
+ var objectCreationExpression = (ObjectCreationExpressionSyntax) context.Node;
+ if (objectCreationExpression.ArgumentList == null || !objectCreationExpression.ArgumentList.Arguments.Any())
{
return;
}
var exceptionType = objectCreationExpression.Type;
var symbolInformation = context.SemanticModel.GetSymbolInfo(exceptionType);
- if (symbolInformation.Symbol.InheritsFrom(typeof (ArgumentException)))
+ if (symbolInformation.Symbol.InheritsFrom(typeof(ArgumentException)))
{
- var arguments =
- objectCreationExpression.ArgumentList.Arguments.Select(x => x.Expression)
- .OfType();
+ var arguments = new List();
+
+ foreach (var argument in objectCreationExpression.ArgumentList.Arguments)
+ {
+ if (argument.Expression is LiteralExpressionSyntax)
+ {
+ arguments.Add((LiteralExpressionSyntax)argument.Expression);
+ }
+ }
+
var methodParameters =
objectCreationExpression.Ancestors()
- .OfType()
- .FirstOrDefault()?
- .ParameterList.Parameters;
+ .OfType(SyntaxKind.MethodDeclaration)
+ .FirstOrDefault()?
+ .ParameterList.Parameters;
+
+ // Exception is declared inside a method
+ if (methodParameters != null)
+ {
+ foreach (var argument in arguments)
+ {
+ var argumentName = argument.Token.ValueText;
+ ParameterSyntax correspondingParameter = null;
+
+ foreach (var parameter in methodParameters)
+ {
+ if (string.Equals((string)parameter.Identifier.Value, argumentName,
+ StringComparison.OrdinalIgnoreCase))
+ {
+ correspondingParameter = parameter;
+ break;
+ }
+ }
+
+ if (correspondingParameter != null)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule, argument.GetLocation(),
+ correspondingParameter.Identifier.Value));
+ return;
+ }
+ }
+ }
+
+ // We also account for the situation where an exception is thrown from a property setter and refers to the contextual keyword "value"
+ var propertyDeclaration = objectCreationExpression.Ancestors()
+ .OfType(SyntaxKind.PropertyDeclaration)
+ .FirstOrDefault();
- // Exception is declared outside a method
- if (methodParameters == null)
+ if (propertyDeclaration == null)
{
return;
}
- foreach (var argument in arguments)
+ foreach (var argument in objectCreationExpression.ArgumentList.Arguments)
{
- var argumentName = argument.Token.ValueText;
- var correspondingParameter =
- methodParameters.Value.FirstOrDefault(
- x =>
- string.Equals((string) x.Identifier.Value, (string) argumentName,
- StringComparison.OrdinalIgnoreCase));
- if (correspondingParameter != null)
+ if (argument.Expression.IsKind(SyntaxKind.StringLiteralExpression))
{
- context.ReportDiagnostic(Diagnostic.Create(Rule, argument.GetLocation(),
- correspondingParameter.Identifier.Value));
- return;
+ var stringLiteral = (LiteralExpressionSyntax) argument.Expression;
+ if (stringLiteral.Token.ValueText == "value")
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule, argument.GetLocation(), "value"));
+ return;
+ }
}
}
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ArgumentExceptionWithoutNameofOperator/ArgumentExceptionWithoutNameofOperatorCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ArgumentExceptionWithoutNameofOperator/ArgumentExceptionWithoutNameofOperatorCodeFix.cs
index 96681b8..030afbf 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ArgumentExceptionWithoutNameofOperator/ArgumentExceptionWithoutNameofOperatorCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ArgumentExceptionWithoutNameofOperator/ArgumentExceptionWithoutNameofOperatorCodeFix.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Immutable;
using System.Composition;
+using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
@@ -8,10 +9,11 @@
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.Exceptions.ArgumentExceptionWithoutNameofOperator
{
- [ExportCodeFixProvider(nameof(ArgumentExceptionWithoutNameofOperatorCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.ArgumentExceptionWithoutNameofOperator + "CF", LanguageNames.CSharp), Shared]
public class ArgumentExceptionWithoutNameofOperatorCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds
@@ -36,32 +38,61 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
ArgumentExceptionWithoutNameofOperatorAnalyzer.Rule.Id), diagnostic);
}
- private Task UseNameofAsync(Document document, SyntaxNode root,
- ObjectCreationExpressionSyntax objectCreationExpression)
+ private Task UseNameofAsync(Document document, SyntaxNode root, ObjectCreationExpressionSyntax objectCreationExpression)
{
- var method = objectCreationExpression.Ancestors().OfType().First();
- var methodParameters = method.ParameterList.Parameters;
+ var method = objectCreationExpression.Ancestors().OfType(SyntaxKind.MethodDeclaration).FirstOrDefault();
+ PropertyDeclarationSyntax property = default(PropertyDeclarationSyntax);
+ if (method == null)
+ {
+ // Fired from a property setter
+ property = objectCreationExpression.Ancestors()
+ .OfType(SyntaxKind.PropertyDeclaration)
+ .First();
+ }
+
var expressionArguments =
objectCreationExpression.ArgumentList.Arguments.Select(x => x.Expression)
- .OfType();
+ .OfType();
foreach (var expressionArgument in expressionArguments)
{
- foreach (var methodParameter in methodParameters)
+ if (property != default(PropertyDeclarationSyntax))
{
- if (string.Equals((string) methodParameter.Identifier.Value, (string) expressionArgument.Token.Value,
- StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(expressionArgument.Token.ValueText, "value", StringComparison.OrdinalIgnoreCase))
{
- var newExpression = SyntaxFactory.ParseExpression($"nameof({methodParameter.Identifier})");
- var newParent = objectCreationExpression.ReplaceNode(expressionArgument, newExpression);
- var newRoot = root.ReplaceNode(objectCreationExpression, newParent);
- var newDocument = document.WithSyntaxRoot(newRoot);
- return Task.FromResult(newDocument.Project.Solution);
+ return CreateNewExpressionAsync(root, "value", objectCreationExpression, expressionArgument, document);
}
}
+ else
+ {
+ Debug.Assert(method != null);
+ var methodParameters = method.ParameterList.Parameters;
+ foreach (var methodParameter in methodParameters)
+ {
+ if (string.Equals(methodParameter.Identifier.ValueText, expressionArgument.Token.ValueText, StringComparison.OrdinalIgnoreCase))
+ {
+ return CreateNewExpressionAsync(root, methodParameter.Identifier.ValueText, objectCreationExpression, expressionArgument, document);
+ }
+ }
+ }
+
}
- return null;
+ throw new InvalidOperationException("No corresponding parameter could be found");
+ }
+
+ private Task CreateNewExpressionAsync(
+ SyntaxNode root,
+ string newIdentifier,
+ ObjectCreationExpressionSyntax objectCreationExpression,
+ ExpressionSyntax argumentExpression,
+ Document document)
+ {
+ var newExpression = SyntaxFactory.ParseExpression($"nameof({newIdentifier})");
+ var newParent = objectCreationExpression.ReplaceNode(argumentExpression, newExpression);
+ var newRoot = root.ReplaceNode(objectCreationExpression, newParent);
+ var newDocument = document.WithSyntaxRoot(newRoot);
+ return Task.FromResult(newDocument.Project.Solution);
}
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/CatchNullReferenceException/CatchingNullReferenceExceptionAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/CatchNullReferenceException/CatchingNullReferenceExceptionAnalyzer.cs
index 1eb8aab..a3a9382 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/CatchNullReferenceException/CatchingNullReferenceExceptionAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/CatchNullReferenceException/CatchingNullReferenceExceptionAnalyzer.cs
@@ -22,16 +22,13 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.CatchDeclaration);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.CatchDeclaration);
private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
{
- var catchDeclaration = context.Node as CatchDeclarationSyntax;
+ var catchDeclaration = (CatchDeclarationSyntax) context.Node;
- var catchType = catchDeclaration?.Type;
+ var catchType = catchDeclaration.Type;
if (catchType == null)
{
return;
@@ -40,7 +37,7 @@ private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
var catchSymbol = context.SemanticModel.GetSymbolInfo(catchType).Symbol;
if (catchSymbol != null)
{
- if (catchSymbol.MetadataName == typeof (NullReferenceException).Name)
+ if (catchSymbol.MetadataName == typeof(NullReferenceException).Name)
{
context.ReportDiagnostic(Diagnostic.Create(Rule, catchDeclaration.GetLocation()));
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/EmptyArgumentException/EmptyArgumentExceptionAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/EmptyArgumentException/EmptyArgumentExceptionAnalyzer.cs
index 2f64023..529ca56 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/EmptyArgumentException/EmptyArgumentExceptionAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/EmptyArgumentException/EmptyArgumentExceptionAnalyzer.cs
@@ -23,23 +23,20 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.ThrowStatement);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.ThrowStatement);
private static void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
{
- var throwStatement = context.Node as ThrowStatementSyntax;
+ var throwStatement = (ThrowStatementSyntax) context.Node;
- var expression = throwStatement?.Expression as ObjectCreationExpressionSyntax;
+ var expression = throwStatement.Expression as ObjectCreationExpressionSyntax;
if (expression == null)
{
return;
}
var symbolInformation = context.SemanticModel.GetSymbolInfo(expression.Type);
- if (!symbolInformation.Symbol.InheritsFrom(typeof (ArgumentException)))
+ if (!symbolInformation.Symbol.InheritsFrom(typeof(ArgumentException)))
{
return;
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/EmptyCatchClause/EmptyCatchClauseAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/EmptyCatchClause/EmptyCatchClauseAnalyzer.cs
index 70770f1..a721f58 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/EmptyCatchClause/EmptyCatchClauseAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/EmptyCatchClause/EmptyCatchClauseAnalyzer.cs
@@ -1,5 +1,4 @@
using System.Collections.Immutable;
-using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -22,15 +21,12 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.CatchClause);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.CatchClause);
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
- var catchClause = context.Node as CatchClauseSyntax;
- if (catchClause?.Block == null)
+ var catchClause = (CatchClauseSyntax) context.Node;
+ if (catchClause.Block == null)
{
return;
}
@@ -40,9 +36,12 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
return;
}
- if (catchClause.Block.CloseBraceToken.LeadingTrivia.Any(x => x.IsCommentTrivia()))
+ foreach (var trivia in catchClause.Block.CloseBraceToken.LeadingTrivia)
{
- return;
+ if (trivia.IsCommentTrivia())
+ {
+ return;
+ }
}
context.ReportDiagnostic(Diagnostic.Create(Rule, catchClause.CatchKeyword.GetLocation()));
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ExceptionThrownFromProhibitedContext/ExceptionThrownFromProhibitedContextAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ExceptionThrownFromProhibitedContext/ExceptionThrownFromProhibitedContextAnalyzer.cs
new file mode 100644
index 0000000..874a1d5
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ExceptionThrownFromProhibitedContext/ExceptionThrownFromProhibitedContextAnalyzer.cs
@@ -0,0 +1,180 @@
+using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.Exceptions.ExceptionThrownFromProhibitedContext
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class ExceptionThrownFromProhibitedContextAnalyzer : DiagnosticAnalyzer
+ {
+ private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
+
+ private static readonly string Category = VSDiagnosticsResources.ExceptionsCategory;
+
+ private static DiagnosticDescriptor ImplicitOperatorRule
+ => new DiagnosticDescriptor(DiagnosticId.ExceptionThrownFromImplicitOperator,
+ VSDiagnosticsResources.ExceptionThrownFromImplicitOperatorAnalyzerTitle,
+ VSDiagnosticsResources.ExceptionThrownFromImplicitOperatorAnalyzerMessage, Category, Severity, true);
+
+ private static DiagnosticDescriptor PropertyGetterRule
+ => new DiagnosticDescriptor(DiagnosticId.ExceptionThrownFromPropertyGetter,
+ VSDiagnosticsResources.ExceptionThrownFromPropertyGetterAnalyzerTitle,
+ VSDiagnosticsResources.ExceptionThrownFromPropertyGetterAnalyzerMessage, Category, Severity, true);
+
+ private static DiagnosticDescriptor StaticConstructorRule
+ => new DiagnosticDescriptor(DiagnosticId.ExceptionThrownFromStaticConstructor,
+ VSDiagnosticsResources.ExceptionThrownFromStaticConstructorAnalyzerTitle,
+ VSDiagnosticsResources.ExceptionThrownFromStaticConstructorAnalyzerMessage, Category, Severity, true);
+
+ private static DiagnosticDescriptor FinallyBlockRule
+ => new DiagnosticDescriptor(DiagnosticId.ExceptionThrownFromFinallyBlock,
+ VSDiagnosticsResources.ExceptionThrownFromFinallyBlockAnalyzerTitle,
+ VSDiagnosticsResources.ExceptionThrownFromFinallyBlockAnalyzerMessage, Category, Severity, true);
+
+ private static DiagnosticDescriptor EqualityOperatorRule
+ => new DiagnosticDescriptor(DiagnosticId.ExceptionThrownFromEqualityOperator,
+ VSDiagnosticsResources.ExceptionThrownFromEqualityOperatorAnalyzerTitle,
+ VSDiagnosticsResources.ExceptionThrownFromEqualityOperatorAnalyzerMessage, Category, Severity, true);
+
+ private static DiagnosticDescriptor DisposeRule
+ => new DiagnosticDescriptor(DiagnosticId.ExceptionThrownFromDispose,
+ VSDiagnosticsResources.ExceptionThrownFromDisposeAnalyzerTitle,
+ VSDiagnosticsResources.ExceptionThrownFromDisposeAnalyzerMessage, Category, Severity, true);
+
+ private static DiagnosticDescriptor FinalizerRule
+ => new DiagnosticDescriptor(DiagnosticId.ExceptionThrownFromFinalizer,
+ VSDiagnosticsResources.ExceptionThrownFromFinalizerAnalyzerTitle,
+ VSDiagnosticsResources.ExceptionThrownFromFinalizerAnalyzerMessage, Category, Severity, true);
+
+ private static DiagnosticDescriptor GetHashCodeRule
+ => new DiagnosticDescriptor(DiagnosticId.ExceptionThrownFromGetHashCode,
+ VSDiagnosticsResources.ExceptionThrownFromGetHashCodeAnalyzerTitle,
+ VSDiagnosticsResources.ExceptionThrownFromGetHashCodeAnalyzerMessage, Category, Severity, true);
+
+ private static DiagnosticDescriptor EqualsRule
+ => new DiagnosticDescriptor(DiagnosticId.ExceptionThrownFromEquals,
+ VSDiagnosticsResources.ExceptionThrownFromEqualsAnalyzerTitle,
+ VSDiagnosticsResources.ExceptionThrownFromEqualsAnalyzerMessage, Category, Severity, true);
+
+ public override ImmutableArray SupportedDiagnostics
+ => ImmutableArray.Create(
+ ImplicitOperatorRule,
+ PropertyGetterRule,
+ StaticConstructorRule,
+ FinallyBlockRule,
+ EqualityOperatorRule,
+ DisposeRule,
+ FinalizerRule,
+ GetHashCodeRule,
+ EqualsRule);
+
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ThrowStatement);
+
+ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
+ {
+ // Since the current node is a throw statement there is no symbol to be found.
+ // Therefore we look at whatever member is holding the statement (constructor, method, property, etc) and see what encloses that
+ var containingType = context.SemanticModel.GetEnclosingSymbol(context.Node.SpanStart).ContainingType;
+ var warningLocation = context.Node.GetLocation();
+
+ foreach (var ancestor in context.Node.Ancestors())
+ {
+ if (ancestor.IsKind(SyntaxKind.MethodDeclaration))
+ {
+ var method = (MethodDeclarationSyntax) ancestor;
+ var methodName = method.Identifier.ValueText;
+
+ if (methodName == "Dispose")
+ {
+ var arity = method.ParameterList.Parameters.Count;
+ context.ReportDiagnostic(Diagnostic.Create(DisposeRule, warningLocation, arity == 0 ? "Dispose()" : "Dispose(bool)", containingType.Name));
+ return;
+ }
+
+ if (methodName == "GetHashCode")
+ {
+ // Make sure we're dealing with the actual members defined in 'Object' in case they're hidden in a subclass
+ var currentMethodSymbol = context.SemanticModel.GetDeclaredSymbol(method);
+
+ var objectSymbol = context.SemanticModel.Compilation.GetSpecialType(SpecialType.System_Object);
+ var objectGetHashCodeSymbol = objectSymbol.GetMembers("GetHashCode").Single();
+
+ while (currentMethodSymbol.IsOverride)
+ {
+ currentMethodSymbol = currentMethodSymbol.OverriddenMethod;
+ }
+
+ if (currentMethodSymbol.Equals(objectGetHashCodeSymbol))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(GetHashCodeRule, warningLocation, containingType.Name));
+ return;
+ }
+ }
+
+ // We don't verify we're dealing with the 'Object' overridden method of 'Equals' because that would exclude Equals(T) in IEquatable
+ // Furthermore we can expect to have multiple overloads of 'Equals' on argument type to provide a better equality comparison experience
+ // This is not the case for GetHashCode() where we only expect one implementation
+ if (methodName == "Equals" && method.ParameterList.Parameters.Count == 1)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(EqualsRule, warningLocation, method.ParameterList.Parameters[0].Type.ToString(), containingType.Name));
+ return;
+ }
+ }
+ else if (ancestor.IsKind(SyntaxKind.GetAccessorDeclaration))
+ {
+ var property = ancestor.Ancestors().OfType(SyntaxKind.PropertyDeclaration).FirstOrDefault();
+ if (property == null)
+ {
+ return;
+ }
+ context.ReportDiagnostic(Diagnostic.Create(PropertyGetterRule, warningLocation, property.Identifier.ValueText));
+ return;
+ }
+ else if (ancestor.IsKind(SyntaxKind.FinallyClause))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(FinallyBlockRule, warningLocation));
+ return;
+ }
+ else if (ancestor.IsKind(SyntaxKind.OperatorDeclaration))
+ {
+ var operatorDeclaration = (OperatorDeclarationSyntax) ancestor;
+ if (operatorDeclaration.OperatorToken.IsKind(SyntaxKind.EqualsEqualsToken) || operatorDeclaration.OperatorToken.IsKind(SyntaxKind.ExclamationEqualsToken))
+ {
+ var operatorToken = operatorDeclaration.OperatorToken.ValueText;
+ var firstType = operatorDeclaration.ParameterList.Parameters[0].Type.ToString();
+ var secondType = operatorDeclaration.ParameterList.Parameters[1].Type.ToString();
+ context.ReportDiagnostic(Diagnostic.Create(EqualityOperatorRule, warningLocation, operatorToken, firstType, secondType, containingType.Name));
+ return;
+ }
+ }
+ else if (ancestor.IsKind(SyntaxKind.ConversionOperatorDeclaration))
+ {
+ var conversionOperatorDeclaration = (ConversionOperatorDeclarationSyntax) ancestor;
+ if (conversionOperatorDeclaration.ImplicitOrExplicitKeyword.IsKind(SyntaxKind.ImplicitKeyword))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(ImplicitOperatorRule, warningLocation, conversionOperatorDeclaration.Type.ToString(), containingType.Name));
+ return;
+ }
+ }
+ else if (ancestor.IsKind(SyntaxKind.ConstructorDeclaration))
+ {
+ var constructor = (ConstructorDeclarationSyntax) ancestor;
+ if (constructor.Modifiers.Any(SyntaxKind.StaticKeyword))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(StaticConstructorRule, warningLocation, containingType.Name));
+ return;
+ }
+ }
+ else if (ancestor.IsKind(SyntaxKind.DestructorDeclaration))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(FinalizerRule, warningLocation, containingType.Name));
+ return;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/RethrowExceptionWithoutLosingStacktrace/RethrowExceptionWithoutLosingStacktraceAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/RethrowExceptionWithoutLosingStacktrace/RethrowExceptionWithoutLosingStacktraceAnalyzer.cs
index f2e8cd7..5705acc 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/RethrowExceptionWithoutLosingStacktrace/RethrowExceptionWithoutLosingStacktraceAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/RethrowExceptionWithoutLosingStacktrace/RethrowExceptionWithoutLosingStacktraceAnalyzer.cs
@@ -13,36 +13,27 @@ namespace VSDiagnostics.Diagnostics.Exceptions.RethrowExceptionWithoutLosingStac
public class RethrowExceptionWithoutLosingStacktraceAnalyzer : DiagnosticAnalyzer
{
private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
-
private static readonly string Category = VSDiagnosticsResources.ExceptionsCategory;
+ private static readonly string Message = VSDiagnosticsResources.RethrowExceptionWithoutLosingStacktraceAnalyzerMessage;
+ private static readonly string Title = VSDiagnosticsResources.RethrowExceptionWithoutLosingStacktraceAnalyzerTitle;
- private static readonly string Message =
- VSDiagnosticsResources.RethrowExceptionWithoutLosingStacktraceAnalyzerMessage;
-
- private static readonly string Title =
- VSDiagnosticsResources.RethrowExceptionWithoutLosingStacktraceAnalyzerTitle;
-
- internal static DiagnosticDescriptor Rule
- => new DiagnosticDescriptor(DiagnosticId.RethrowExceptionWithoutLosingStacktrace, Title, Message, Category, Severity, true);
+ internal static DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId.RethrowExceptionWithoutLosingStacktrace, Title, Message, Category, Severity, true);
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ThrowStatement);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ThrowStatement);
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
- var throwStatement = context.Node as ThrowStatementSyntax;
+ var throwStatement = (ThrowStatementSyntax) context.Node;
- var throwIdentifierSyntax = throwStatement?.Expression as IdentifierNameSyntax;
+ var throwIdentifierSyntax = throwStatement.Expression as IdentifierNameSyntax;
if (throwIdentifierSyntax == null)
{
return;
}
- var catchClause = throwStatement.Ancestors().OfType().FirstOrDefault();
+ var catchClause = throwStatement.Ancestors().OfType(SyntaxKind.CatchClause).FirstOrDefault();
// Code is in an incomplete state (user is typing the catch clause but hasn't typed the identifier yet)
var exceptionIdentifier = catchClause?.Declaration?.Identifier;
@@ -51,10 +42,10 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
return;
}
- var catchClauseIdentifier = exceptionIdentifier.Value.ToString();
- var thrownIdentifier = throwIdentifierSyntax.Identifier.Value.ToString();
+ var catchClauseIdentifier = exceptionIdentifier.Value.ValueText;
+ var thrownIdentifier = throwIdentifierSyntax.Identifier.ValueText;
- if (string.Equals(catchClauseIdentifier, thrownIdentifier, StringComparison.Ordinal))
+ if (catchClauseIdentifier == thrownIdentifier)
{
context.ReportDiagnostic(Diagnostic.Create(Rule, throwStatement.GetLocation()));
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/RethrowExceptionWithoutLosingStacktrace/RethrowExceptionWithoutLosingStacktraceCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/RethrowExceptionWithoutLosingStacktrace/RethrowExceptionWithoutLosingStacktraceCodeFix.cs
index 156c00c..f51d0f1 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/RethrowExceptionWithoutLosingStacktrace/RethrowExceptionWithoutLosingStacktraceCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/RethrowExceptionWithoutLosingStacktrace/RethrowExceptionWithoutLosingStacktraceCodeFix.cs
@@ -7,10 +7,11 @@
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.Exceptions.RethrowExceptionWithoutLosingStacktrace
{
- [ExportCodeFixProvider(nameof(RethrowExceptionWithoutLosingStacktraceCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.RethrowExceptionWithoutLosingStacktrace + "CF", LanguageNames.CSharp), Shared]
public class RethrowExceptionWithoutLosingStacktraceCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds
@@ -32,7 +33,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
}
private Task RemoveRethrowAsync(Document document, SyntaxNode root,
- ThrowStatementSyntax throwStatement)
+ ThrowStatementSyntax throwStatement)
{
var newStatement = SyntaxFactory.ThrowStatement();
var newRoot = root.ReplaceNode(throwStatement, newStatement);
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/SingleGeneralException/SingleGeneralExceptionAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/SingleGeneralException/SingleGeneralExceptionAnalyzer.cs
index b38eb80..f5d877c 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/SingleGeneralException/SingleGeneralExceptionAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/SingleGeneralException/SingleGeneralExceptionAnalyzer.cs
@@ -18,19 +18,16 @@ public class SingleGeneralExceptionAnalyzer : DiagnosticAnalyzer
private static readonly string Title = VSDiagnosticsResources.SingleGeneralExceptionAnalyzerTitle;
internal static DiagnosticDescriptor Rule
- => new DiagnosticDescriptor(DiagnosticId.SingleGeneralException, Title, Message, Category, Severity, true);
+ => new DiagnosticDescriptor(DiagnosticId.SingleGeneralException, Title, Message, Category, Severity, isEnabledByDefault: false);
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.TryStatement);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.TryStatement);
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
- var tryStatement = context.Node as TryStatementSyntax;
- if (tryStatement?.Catches.Count != 1)
+ var tryStatement = (TryStatementSyntax) context.Node;
+ if (tryStatement.Catches.Count != 1)
{
return;
}
@@ -45,7 +42,7 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
var symbol = context.SemanticModel.GetSymbolInfo(declaredException).Symbol;
if (symbol != null)
{
- if (symbol.MetadataName == typeof (Exception).Name)
+ if (symbol.MetadataName == typeof(Exception).Name)
{
context.ReportDiagnostic(Diagnostic.Create(Rule, declaredException.GetLocation()));
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ThrowNull/ThrowNullAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ThrowNull/ThrowNullAnalyzer.cs
new file mode 100644
index 0000000..a3fe2d1
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/Exceptions/ThrowNull/ThrowNullAnalyzer.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.Exceptions.ThrowNull
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class ThrowNullAnalyzer : DiagnosticAnalyzer
+ {
+ private const DiagnosticSeverity Severity = DiagnosticSeverity.Error;
+
+ private static readonly string Category = VSDiagnosticsResources.ExceptionsCategory;
+ private static readonly string Message = VSDiagnosticsResources.ThrowNullMessage;
+ private static readonly string Title = VSDiagnosticsResources.ThrowNullMessage;
+
+ internal static DiagnosticDescriptor Rule
+ => new DiagnosticDescriptor(DiagnosticId.ThrowNull, Title, Message, Category, Severity, isEnabledByDefault: true);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ThrowStatement);
+
+ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
+ {
+ var throwStatement = (ThrowStatementSyntax) context.Node;
+
+ var throwValue = context.SemanticModel.GetConstantValue(throwStatement.Expression);
+ if (throwValue.HasValue && throwValue.Value == null)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule, throwStatement.Expression.GetLocation()));
+ }
+ }
+ }
+}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/AsToCast/AsToCastAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/AsToCast/AsToCastAnalyzer.cs
index 18898e5..d5ece8e 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/AsToCast/AsToCastAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/AsToCast/AsToCastAnalyzer.cs
@@ -1,7 +1,6 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using VSDiagnostics.Utilities;
@@ -16,25 +15,12 @@ public class AsToCastAnalyzer : DiagnosticAnalyzer
private static readonly string Message = VSDiagnosticsResources.AsToCastAnalyzerMessage;
private static readonly string Title = VSDiagnosticsResources.AsToCastAnalyzerTitle;
- internal static DiagnosticDescriptor Rule
- => new DiagnosticDescriptor(DiagnosticId.AsToCast, Title, Message, Category, Severity, true);
+ internal static DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId.AsToCast, Title, Message, Category, Severity, true);
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.AsExpression);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.AsExpression);
- private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
- {
- var binaryExpression = context.Node as BinaryExpressionSyntax;
- if (binaryExpression == null)
- {
- return;
- }
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, binaryExpression.GetLocation()));
- }
+ private static void AnalyzeSymbol(SyntaxNodeAnalysisContext context) => context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation()));
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/AsToCast/AsToCastCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/AsToCast/AsToCastCodeFix.cs
index b6e8a3d..0a7098e 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/AsToCast/AsToCastCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/AsToCast/AsToCastCodeFix.cs
@@ -8,10 +8,11 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.General.AsToCast
{
- [ExportCodeFixProvider(nameof(AsToCastCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.AsToCast + "CF", LanguageNames.CSharp), Shared]
public class AsToCastCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AsToCastAnalyzer.Rule.Id);
@@ -24,24 +25,20 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
- var statement = root.FindNode(diagnosticSpan);
+ var statement = root.FindNode(diagnosticSpan).DescendantNodesAndSelf().OfType().First();
context.RegisterCodeFix(
CodeAction.Create(VSDiagnosticsResources.AsToCastCodeFixTitle,
x => AsToCastAsync(context.Document, root, statement), AsToCastAnalyzer.Rule.Id), diagnostic);
}
- private Task AsToCastAsync(Document document, SyntaxNode root, SyntaxNode statement)
+ private Task AsToCastAsync(Document document, SyntaxNode root, SyntaxNode statement)
{
var binaryExpression = (BinaryExpressionSyntax) statement;
- var typeSyntax = SyntaxFactory.ParseTypeName(binaryExpression.Right.GetText().ToString());
- var newExpression =
- SyntaxFactory.CastExpression(typeSyntax, binaryExpression.Left)
- .WithAdditionalAnnotations(Formatter.Annotation);
+ var typeSyntax = (TypeSyntax) binaryExpression.Right;
- var newRoot = root.ReplaceNode(binaryExpression, newExpression);
-
- var newDocument = document.WithSyntaxRoot(newRoot);
- return Task.FromResult(newDocument.Project.Solution);
+ var newExpression = SyntaxFactory.CastExpression(typeSyntax, binaryExpression.Left).WithAdditionalAnnotations(Formatter.Annotation);
+ root = root.ReplaceNode(binaryExpression, newExpression);
+ return Task.FromResult(document.WithSyntaxRoot(root));
}
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CastToAs/CastToAsAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CastToAs/CastToAsAnalyzer.cs
index 1278988..dd37038 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CastToAs/CastToAsAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CastToAs/CastToAsAnalyzer.cs
@@ -21,26 +21,24 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.CastExpression);
+
+ ///
+ /// We don't handle situations like
+ /// int x = (int) o;
+ /// Turning this into a soft cast (o as int?) would cause issues when trying to apply this to a generic definition
+ /// This is only needed for non-nullable valuetypes because they need to become nullable for this kind of cast
+ ///
+ private static void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.CastExpression);
- }
-
- private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
- {
- var castExpression = context.Node as CastExpressionSyntax;
- if (castExpression == null)
- {
- return;
- }
-
- var castedTypeInfo = context.SemanticModel.GetTypeInfo(castExpression.Expression);
- if (castedTypeInfo.ConvertedType != null && castedTypeInfo.ConvertedType.IsValueType)
+ var castExpression = (CastExpressionSyntax) context.Node;
+ var type = context.SemanticModel.GetTypeInfo(castExpression.Type).Type;
+ if (type.IsValueType && type.OriginalDefinition.SpecialType != SpecialType.System_Nullable_T)
{
return;
}
- context.ReportDiagnostic(Diagnostic.Create(Rule, castExpression.GetLocation()));
+ context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation()));
}
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CastToAs/CastToAsCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CastToAs/CastToAsCodeFix.cs
index 9421121..2921fb4 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CastToAs/CastToAsCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CastToAs/CastToAsCodeFix.cs
@@ -8,10 +8,11 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.General.CastToAs
{
- [ExportCodeFixProvider(nameof(CastToAsCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.CastToAs + "CF", LanguageNames.CSharp), Shared]
public class CastToAsCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CastToAsAnalyzer.Rule.Id);
@@ -24,7 +25,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
- var statement = root.FindNode(diagnosticSpan);
+ var statement = root.FindNode(diagnosticSpan).DescendantNodesAndSelf().OfType().First();
context.RegisterCodeFix(
CodeAction.Create(VSDiagnosticsResources.CastToAsCodeFixTitle,
x => CastToAsAsync(context.Document, root, statement), CastToAsAnalyzer.Rule.Id), diagnostic);
@@ -33,14 +34,11 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
private Task CastToAsAsync(Document document, SyntaxNode root, SyntaxNode statement)
{
var castExpression = (CastExpressionSyntax) statement;
- var newExpression =
- SyntaxFactory.BinaryExpression(SyntaxKind.AsExpression, castExpression.Expression, castExpression.Type)
- .WithAdditionalAnnotations(Formatter.Annotation);
+ var newExpression = SyntaxFactory.BinaryExpression(SyntaxKind.AsExpression, castExpression.Expression, castExpression.Type)
+ .WithAdditionalAnnotations(Formatter.Annotation);
- var newRoot = root.ReplaceNode(castExpression, newExpression);
-
- var newDocument = document.WithSyntaxRoot(newRoot);
- return Task.FromResult(newDocument.Project.Solution);
+ root = root.ReplaceNode(castExpression, newExpression);
+ return Task.FromResult(document.WithSyntaxRoot(root).Project.Solution);
}
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToFalseLiteral/CompareBooleanToFalseLiteralAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToFalseLiteral/CompareBooleanToFalseLiteralAnalyzer.cs
index 18b3ac5..ac0b5c9 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToFalseLiteral/CompareBooleanToFalseLiteralAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToFalseLiteral/CompareBooleanToFalseLiteralAnalyzer.cs
@@ -21,18 +21,11 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.FalseLiteralExpression);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.FalseLiteralExpression);
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
- var literalExpression = context.Node as LiteralExpressionSyntax;
- if (literalExpression == null)
- {
- return;
- }
+ var literalExpression = (LiteralExpressionSyntax) context.Node;
if (!(literalExpression.Token.IsKind(SyntaxKind.FalseKeyword) && literalExpression.Token.Value is bool))
{
@@ -54,7 +47,7 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
return;
}
- if (rightSymbol.Type.IsNullable())
+ if (rightSymbol.Type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
{
return;
}
@@ -68,7 +61,7 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
return;
}
- if (leftSymbol.Type.IsNullable())
+ if (leftSymbol.Type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
{
return;
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToFalseLiteral/CompareBooleanToFalseLiteralCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToFalseLiteral/CompareBooleanToFalseLiteralCodeFix.cs
index 2678ed2..b9e973d 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToFalseLiteral/CompareBooleanToFalseLiteralCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToFalseLiteral/CompareBooleanToFalseLiteralCodeFix.cs
@@ -9,12 +9,24 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.General.CompareBooleanToFalseLiteral
{
- [ExportCodeFixProvider(nameof(CompareBooleanToFalseLiteralCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.CompareBooleanToFalseLiteral + "CF", LanguageNames.CSharp), Shared]
public class CompareBooleanToFalseLiteralCodeFix : CodeFixProvider
{
+ private static readonly Dictionary MapOperatorToReverseOperator =
+ new Dictionary
+ {
+ { SyntaxKind.EqualsEqualsToken, SyntaxKind.ExclamationEqualsToken },
+ { SyntaxKind.ExclamationEqualsToken, SyntaxKind.EqualsEqualsToken },
+ { SyntaxKind.GreaterThanEqualsToken, SyntaxKind.LessThanToken },
+ { SyntaxKind.LessThanToken, SyntaxKind.GreaterThanEqualsToken },
+ { SyntaxKind.LessThanEqualsToken, SyntaxKind.GreaterThanToken },
+ { SyntaxKind.GreaterThanToken, SyntaxKind.LessThanEqualsToken }
+ };
+
public override ImmutableArray FixableDiagnosticIds
=> ImmutableArray.Create(CompareBooleanToFalseLiteralAnalyzer.Rule.Id);
@@ -54,7 +66,7 @@ private Task SimplifyExpressionAsync(Document document, SyntaxNode roo
var newOperator = binaryExpression.OperatorToken.IsKind(SyntaxKind.EqualsEqualsToken)
? MapOperatorToReverseOperator.First(kvp => kvp.Key == internalBinaryExpression.OperatorToken.Kind())
- .Value
+ .Value
: internalBinaryExpression.OperatorToken.Kind();
newExpression = internalBinaryExpression.WithOperatorToken(SyntaxFactory.Token(newOperator));
@@ -73,21 +85,10 @@ private Task SimplifyExpressionAsync(Document document, SyntaxNode roo
}
var newRoot =
- root.ReplaceNode(binaryExpression, newExpression).WithAdditionalAnnotations(Formatter.Annotation);
+ root.ReplaceNode(binaryExpression, newExpression.WithAdditionalAnnotations(Formatter.Annotation));
var newDocument = document.WithSyntaxRoot(newRoot);
return Task.FromResult(newDocument.Project.Solution);
}
-
- private static readonly Dictionary MapOperatorToReverseOperator =
- new Dictionary
- {
- {SyntaxKind.EqualsEqualsToken, SyntaxKind.ExclamationEqualsToken},
- {SyntaxKind.ExclamationEqualsToken, SyntaxKind.EqualsEqualsToken},
- {SyntaxKind.GreaterThanEqualsToken, SyntaxKind.LessThanToken},
- {SyntaxKind.LessThanToken, SyntaxKind.GreaterThanEqualsToken},
- {SyntaxKind.LessThanEqualsToken, SyntaxKind.GreaterThanToken},
- {SyntaxKind.GreaterThanToken, SyntaxKind.LessThanEqualsToken},
- };
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToTrueLiteral/CompareBooleanToTrueLiteralAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToTrueLiteral/CompareBooleanToTrueLiteralAnalyzer.cs
index d8900d6..76dc3d7 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToTrueLiteral/CompareBooleanToTrueLiteralAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToTrueLiteral/CompareBooleanToTrueLiteralAnalyzer.cs
@@ -21,18 +21,11 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.TrueLiteralExpression);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.TrueLiteralExpression);
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
- var literalExpression = context.Node as LiteralExpressionSyntax;
- if (literalExpression == null)
- {
- return;
- }
+ var literalExpression = (LiteralExpressionSyntax) context.Node;
if (!(literalExpression.Token.IsKind(SyntaxKind.TrueKeyword) && literalExpression.Token.Value is bool))
{
@@ -54,7 +47,7 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
return;
}
- if (rightSymbol.Type.IsNullable())
+ if (rightSymbol.Type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
{
return;
}
@@ -68,7 +61,7 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
return;
}
- if (leftSymbol.Type.IsNullable())
+ if (leftSymbol.Type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
{
return;
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToTrueLiteral/CompareBooleanToTrueLiteralCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToTrueLiteral/CompareBooleanToTrueLiteralCodeFix.cs
index 3143c8f..06c79b9 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToTrueLiteral/CompareBooleanToTrueLiteralCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/CompareBooleanToTrueLiteral/CompareBooleanToTrueLiteralCodeFix.cs
@@ -9,12 +9,24 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.General.CompareBooleanToTrueLiteral
{
- [ExportCodeFixProvider(nameof(CompareBooleanToTrueLiteralCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.CompareBooleanToTrueLiteral + "CF", LanguageNames.CSharp), Shared]
public class CompareBooleanToTrueLiteralCodeFix : CodeFixProvider
{
+ private static readonly Dictionary MapOperatorToReverseOperator =
+ new Dictionary
+ {
+ { SyntaxKind.EqualsEqualsToken, SyntaxKind.ExclamationEqualsToken },
+ { SyntaxKind.ExclamationEqualsToken, SyntaxKind.EqualsEqualsToken },
+ { SyntaxKind.GreaterThanEqualsToken, SyntaxKind.LessThanToken },
+ { SyntaxKind.LessThanToken, SyntaxKind.GreaterThanEqualsToken },
+ { SyntaxKind.LessThanEqualsToken, SyntaxKind.GreaterThanToken },
+ { SyntaxKind.GreaterThanToken, SyntaxKind.LessThanEqualsToken }
+ };
+
public override ImmutableArray FixableDiagnosticIds
=> ImmutableArray.Create(CompareBooleanToTrueLiteralAnalyzer.Rule.Id);
@@ -55,7 +67,7 @@ private Task SimplifyExpressionAsync(Document document, SyntaxNode roo
var newOperator = binaryExpression.OperatorToken.IsKind(SyntaxKind.EqualsEqualsToken)
? internalBinaryExpression.OperatorToken.Kind()
: MapOperatorToReverseOperator.First(kvp => kvp.Key == internalBinaryExpression.OperatorToken.Kind())
- .Value;
+ .Value;
newExpression = internalBinaryExpression.WithOperatorToken(SyntaxFactory.Token(newOperator));
}
@@ -73,21 +85,10 @@ private Task SimplifyExpressionAsync(Document document, SyntaxNode roo
}
var newRoot =
- root.ReplaceNode(binaryExpression, newExpression).WithAdditionalAnnotations(Formatter.Annotation);
+ root.ReplaceNode(binaryExpression, newExpression.WithAdditionalAnnotations(Formatter.Annotation));
var newDocument = document.WithSyntaxRoot(newRoot);
return Task.FromResult(newDocument.Project.Solution);
}
-
- private static readonly Dictionary MapOperatorToReverseOperator =
- new Dictionary
- {
- {SyntaxKind.EqualsEqualsToken, SyntaxKind.ExclamationEqualsToken},
- {SyntaxKind.ExclamationEqualsToken, SyntaxKind.EqualsEqualsToken},
- {SyntaxKind.GreaterThanEqualsToken, SyntaxKind.LessThanToken},
- {SyntaxKind.LessThanToken, SyntaxKind.GreaterThanEqualsToken},
- {SyntaxKind.LessThanEqualsToken, SyntaxKind.GreaterThanToken},
- {SyntaxKind.GreaterThanToken, SyntaxKind.LessThanEqualsToken},
- };
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsAlwaysFalse/ConditionIsAlwaysFalseAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsAlwaysFalse/ConditionIsAlwaysFalseAnalyzer.cs
deleted file mode 100644
index 0d02976..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsAlwaysFalse/ConditionIsAlwaysFalseAnalyzer.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System.Collections.Immutable;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Diagnostics;
-using VSDiagnostics.Utilities;
-
-namespace VSDiagnostics.Diagnostics.General.ConditionIsAlwaysFalse
-{
- [DiagnosticAnalyzer(LanguageNames.CSharp)]
- internal class ConditionIsAlwaysFalseAnalyzer : DiagnosticAnalyzer
- {
- private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
-
- private static readonly string Category = VSDiagnosticsResources.GeneralCategory;
- private static readonly string Message = VSDiagnosticsResources.ConditionIsAlwaysFalseAnalyzerMessage;
- private static readonly string Title = VSDiagnosticsResources.ConditionIsAlwaysFalseAnalyzerTitle;
-
- internal static DiagnosticDescriptor Rule
- => new DiagnosticDescriptor(DiagnosticId.ConditionIsAlwaysFalse, Title, Message, Category, Severity, true);
-
- public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
-
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.IfStatement);
- }
-
- private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
- {
- var ifStatement = (IfStatementSyntax) context.Node;
-
- if (ifStatement.Condition.IsKind(SyntaxKind.FalseLiteralExpression))
- {
- context.ReportDiagnostic(Diagnostic.Create(Rule, ifStatement.Condition.GetLocation()));
- }
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsAlwaysFalse/ConditionIsAlwaysFalseCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsAlwaysFalse/ConditionIsAlwaysFalseCodeFix.cs
deleted file mode 100644
index 8e9433f..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsAlwaysFalse/ConditionIsAlwaysFalseCodeFix.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-using System.Collections.Immutable;
-using System.Composition;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CodeActions;
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Formatting;
-
-namespace VSDiagnostics.Diagnostics.General.ConditionIsAlwaysFalse
-{
- [ExportCodeFixProvider(nameof(ConditionIsAlwaysFalseCodeFix), LanguageNames.CSharp), Shared]
- public class ConditionIsAlwaysFalseCodeFix : CodeFixProvider
- {
- public override ImmutableArray FixableDiagnosticIds
- => ImmutableArray.Create(ConditionIsAlwaysFalseAnalyzer.Rule.Id);
-
- public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
-
- public override async Task RegisterCodeFixesAsync(CodeFixContext context)
- {
- var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
- var diagnostic = context.Diagnostics.First();
- var diagnosticSpan = diagnostic.Location.SourceSpan;
-
- var statement = root.FindNode(diagnosticSpan);
- context.RegisterCodeFix(
- CodeAction.Create(VSDiagnosticsResources.ConditionIsAlwaysTrueCodeFixTitle,
- x => RemoveConditionAsync(context.Document, root, statement), ConditionIsAlwaysFalseAnalyzer.Rule.Id),
- diagnostic);
- }
-
- private Task RemoveConditionAsync(Document document, SyntaxNode root, SyntaxNode statement)
- {
- var ifStatement = statement.Ancestors().OfType().First();
- var blockStatement = ifStatement.Else?.Statement as BlockSyntax;
-
- // no else
- var newRoot =
- root.RemoveNode(ifStatement, SyntaxRemoveOptions.KeepNoTrivia)
- .WithAdditionalAnnotations(Formatter.Annotation);
-
- // else with braces
- if (blockStatement != null)
- {
- newRoot =
- root.ReplaceNode(ifStatement, blockStatement.Statements)
- .WithAdditionalAnnotations(Formatter.Annotation);
- }
-
- // else without braces
- if (ifStatement.Else != null && blockStatement == null)
- {
- newRoot =
- root.ReplaceNode(ifStatement, ifStatement.Else.Statement)
- .WithAdditionalAnnotations(Formatter.Annotation);
- }
-
- var newDocument = document.WithSyntaxRoot(newRoot);
- return Task.FromResult(newDocument.Project.Solution);
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsAlwaysTrue/ConditionIsAlwaysTrueCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsAlwaysTrue/ConditionIsAlwaysTrueCodeFix.cs
deleted file mode 100644
index f6daddb..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsAlwaysTrue/ConditionIsAlwaysTrueCodeFix.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using System.Collections.Immutable;
-using System.Composition;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CodeActions;
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Formatting;
-
-namespace VSDiagnostics.Diagnostics.General.ConditionIsAlwaysTrue
-{
- [ExportCodeFixProvider(nameof(ConditionIsAlwaysTrueCodeFix), LanguageNames.CSharp), Shared]
- public class ConditionIsAlwaysTrueCodeFix : CodeFixProvider
- {
- public override ImmutableArray FixableDiagnosticIds
- => ImmutableArray.Create(ConditionIsAlwaysTrueAnalyzer.Rule.Id);
-
- public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
-
- public override async Task RegisterCodeFixesAsync(CodeFixContext context)
- {
- var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
- var diagnostic = context.Diagnostics.First();
- var diagnosticSpan = diagnostic.Location.SourceSpan;
-
- var statement = root.FindNode(diagnosticSpan);
- context.RegisterCodeFix(
- CodeAction.Create(VSDiagnosticsResources.ConditionIsAlwaysTrueCodeFixTitle,
- x => RemoveConditionAsync(context.Document, root, statement), ConditionIsAlwaysTrueAnalyzer.Rule.Id),
- diagnostic);
- }
-
- private Task RemoveConditionAsync(Document document, SyntaxNode root, SyntaxNode statement)
- {
- var ifStatement = statement.Ancestors().OfType().First();
-
- var blockStatement = ifStatement.Statement as BlockSyntax;
-
- var newRoot = blockStatement == null
- ? root.ReplaceNode(ifStatement, ifStatement.Statement).WithAdditionalAnnotations(Formatter.Annotation)
- : root.ReplaceNode(ifStatement, blockStatement.Statements).WithAdditionalAnnotations(Formatter.Annotation);
-
- var newDocument = document.WithSyntaxRoot(newRoot);
- return Task.FromResult(newDocument.Project.Solution);
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsConstant/ConditionIsConstantAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsConstant/ConditionIsConstantAnalyzer.cs
new file mode 100644
index 0000000..f727b4a
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsConstant/ConditionIsConstantAnalyzer.cs
@@ -0,0 +1,55 @@
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.General.ConditionIsConstant
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class ConditionIsConstantAnalyzer : DiagnosticAnalyzer
+ {
+ private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
+
+ private static readonly string Category = VSDiagnosticsResources.GeneralCategory;
+ private static readonly string Message = VSDiagnosticsResources.ConditionIsConstantAnalyzerMessage;
+ private static readonly string Title = VSDiagnosticsResources.ConditionIsConstantAnalyzerTitle;
+
+ internal static DiagnosticDescriptor Rule
+ => new DiagnosticDescriptor(DiagnosticId.ConditionIsConstant, Title, Message, Category, Severity, true);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.IfStatement);
+
+ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
+ {
+ var ifStatement = (IfStatementSyntax) context.Node;
+
+ var constantValue = context.SemanticModel.GetConstantValue(ifStatement.Condition);
+
+ if (!constantValue.HasValue)
+ {
+ return;
+ }
+
+ if ((bool) constantValue.Value)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule,
+ ifStatement.Condition.GetLocation(),
+ ImmutableDictionary.CreateRange(new[] { new KeyValuePair("IsConditionTrue", "true") }),
+ "true"));
+ }
+
+ if (!(bool) constantValue.Value)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule,
+ ifStatement.Condition.GetLocation(),
+ ImmutableDictionary.CreateRange(new[] { new KeyValuePair("IsConditionTrue", "false") }),
+ "false"));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsConstant/ConditionIsConstantCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsConstant/ConditionIsConstantCodeFix.cs
new file mode 100644
index 0000000..8fbb81d
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionIsConstant/ConditionIsConstantCodeFix.cs
@@ -0,0 +1,127 @@
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Formatting;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.General.ConditionIsConstant
+{
+ [ExportCodeFixProvider(DiagnosticId.ConditionIsConstant + "CF", LanguageNames.CSharp), Shared]
+ public class ConditionIsConstantCodeFix : CodeFixProvider
+ {
+ public override ImmutableArray FixableDiagnosticIds
+ => ImmutableArray.Create(ConditionIsConstantAnalyzer.Rule.Id);
+
+ public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
+
+ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+ var diagnostic = context.Diagnostics.First();
+ var diagnosticSpan = diagnostic.Location.SourceSpan;
+
+ var statement = root.FindNode(diagnosticSpan);
+
+ if (bool.Parse(diagnostic.Properties["IsConditionTrue"]))
+ {
+ context.RegisterCodeFix(
+ CodeAction.Create(VSDiagnosticsResources.ConditionIsConstantCodeFixTitle,
+ x => RemoveConstantTrueConditionAsync(context.Document, root, statement),
+ ConditionIsConstantAnalyzer.Rule.Id),
+ diagnostic);
+ }
+ else
+ {
+ context.RegisterCodeFix(
+ CodeAction.Create(VSDiagnosticsResources.ConditionIsConstantCodeFixTitle,
+ x => RemoveConstantFalseConditionAsync(context.Document, root, statement),
+ ConditionIsConstantAnalyzer.Rule.Id),
+ diagnostic);
+ }
+ }
+
+ private Task RemoveConstantTrueConditionAsync(Document document, SyntaxNode root, SyntaxNode statement)
+ {
+ var ifStatement = statement.Ancestors().OfType().First();
+
+ var blockStatement = ifStatement.Statement as BlockSyntax;
+
+ SyntaxNode newRoot;
+
+ /* this condition will be true when the `if` does not have braces:
+
+ if (condition) statement;
+ */
+ if (blockStatement == null)
+ {
+ newRoot = root.ReplaceNode(ifStatement, ifStatement.Statement).WithAdditionalAnnotations(Formatter.Annotation);
+ }
+ else
+ {
+ /* if the if statement's parent is `SyntaxKind.ElseClause`,
+ the `else` does not have braces and needs the entire `if` block, braces and all:
+
+ else if (condition) { statement; }
+
+ otherwise, the block is already there and we need to replace `if` with just the block statements
+ also covers the general `if`-with-braces condition
+
+ else { if (condition) { statements; } }
+ if (condition) { statements; }
+ */
+ newRoot = ifStatement.Parent.IsKind(SyntaxKind.ElseClause)
+ ? root.ReplaceNode(ifStatement, blockStatement).WithAdditionalAnnotations(Formatter.Annotation)
+ : root.ReplaceNode(ifStatement, blockStatement.Statements).WithAdditionalAnnotations(Formatter.Annotation);
+ }
+
+ var newDocument = document.WithSyntaxRoot(newRoot);
+ return Task.FromResult(newDocument.Project.Solution);
+ }
+
+ private Task RemoveConstantFalseConditionAsync(Document document, SyntaxNode root, SyntaxNode statement)
+ {
+ var ifStatement = statement.Ancestors().OfType().First();
+ var blockStatement = ifStatement.Else?.Statement as BlockSyntax;
+
+ SyntaxNode newRoot;
+
+ // all `if` conditions without being directly in a parent `else`
+ if (!ifStatement.Parent.IsKind(SyntaxKind.ElseClause))
+ {
+ // no else
+ newRoot =
+ root.RemoveNode(ifStatement, SyntaxRemoveOptions.KeepNoTrivia)
+ .WithAdditionalAnnotations(Formatter.Annotation);
+
+ // else with braces
+ if (blockStatement != null)
+ {
+ newRoot =
+ root.ReplaceNode(ifStatement, blockStatement.Statements)
+ .WithAdditionalAnnotations(Formatter.Annotation);
+ }
+
+ // else without braces
+ if (ifStatement.Else != null && blockStatement == null)
+ {
+ newRoot =
+ root.ReplaceNode(ifStatement, ifStatement.Else.Statement)
+ .WithAdditionalAnnotations(Formatter.Annotation);
+ }
+ }
+ else
+ {
+ newRoot = root.RemoveNode(ifStatement.Parent, SyntaxRemoveOptions.KeepLeadingTrivia & SyntaxRemoveOptions.KeepTrailingTrivia);
+ }
+
+ var newDocument = document.WithSyntaxRoot(newRoot);
+ return Task.FromResult(newDocument.Project.Solution);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsDefaultOptions/ConditionalOperatorReturnsDefaultOptionsAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsDefaultOptions/ConditionalOperatorReturnsDefaultOptionsAnalyzer.cs
index 002779d..f9c90b9 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsDefaultOptions/ConditionalOperatorReturnsDefaultOptionsAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsDefaultOptions/ConditionalOperatorReturnsDefaultOptionsAnalyzer.cs
@@ -25,16 +25,13 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.ConditionalExpression);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.ConditionalExpression);
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
- var conditionalExpression = context.Node as ConditionalExpressionSyntax;
+ var conditionalExpression = (ConditionalExpressionSyntax) context.Node;
- var trueExpression = conditionalExpression?.WhenTrue as LiteralExpressionSyntax;
+ var trueExpression = conditionalExpression.WhenTrue as LiteralExpressionSyntax;
if (trueExpression == null)
{
return;
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsDefaultOptions/ConditionalOperatorReturnsDefaultOptionsCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsDefaultOptions/ConditionalOperatorReturnsDefaultOptionsCodeFix.cs
index cbea9f5..31cff54 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsDefaultOptions/ConditionalOperatorReturnsDefaultOptionsCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsDefaultOptions/ConditionalOperatorReturnsDefaultOptionsCodeFix.cs
@@ -7,10 +7,11 @@
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.General.ConditionalOperatorReturnsDefaultOptions
{
- [ExportCodeFixProvider(nameof(ConditionalOperatorReturnsDefaultOptionsCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.ConditionalOperatorReturnsDefaultOptions + "CF", LanguageNames.CSharp), Shared]
public class ConditionalOperatorReturnsDefaultOptionsCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds
@@ -36,8 +37,7 @@ private Task RemoveConditionalAsync(Document document, SyntaxNode root
var conditionalExpression = (ConditionalExpressionSyntax) statement;
var newRoot =
- root.ReplaceNode(conditionalExpression, conditionalExpression.Condition)
- .WithAdditionalAnnotations(Formatter.Annotation);
+ root.ReplaceNode(conditionalExpression, conditionalExpression.Condition.WithAdditionalAnnotations(Formatter.Annotation));
var newDocument = document.WithSyntaxRoot(newRoot);
return Task.FromResult(newDocument.Project.Solution);
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsInvertedDefaultOptions/ConditionalOperatorReturnsInvertedDefaultOptionsAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsInvertedDefaultOptions/ConditionalOperatorReturnsInvertedDefaultOptionsAnalyzer.cs
index ae08fb7..a54320a 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsInvertedDefaultOptions/ConditionalOperatorReturnsInvertedDefaultOptionsAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsInvertedDefaultOptions/ConditionalOperatorReturnsInvertedDefaultOptionsAnalyzer.cs
@@ -25,16 +25,13 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.ConditionalExpression);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.ConditionalExpression);
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
- var conditionalExpression = context.Node as ConditionalExpressionSyntax;
+ var conditionalExpression = (ConditionalExpressionSyntax) context.Node;
- var trueExpression = conditionalExpression?.WhenTrue as LiteralExpressionSyntax;
+ var trueExpression = conditionalExpression.WhenTrue as LiteralExpressionSyntax;
if (trueExpression == null)
{
return;
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsInvertedDefaultOptions/ConditionalOperatorReturnsInvertedDefaultOptionsCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsInvertedDefaultOptions/ConditionalOperatorReturnsInvertedDefaultOptionsCodeFix.cs
index a2e2e9f..472b580 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsInvertedDefaultOptions/ConditionalOperatorReturnsInvertedDefaultOptionsCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ConditionalOperatorReturnsInvertedDefaultOptions/ConditionalOperatorReturnsInvertedDefaultOptionsCodeFix.cs
@@ -8,10 +8,11 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.General.ConditionalOperatorReturnsInvertedDefaultOptions
{
- [ExportCodeFixProvider(nameof(ConditionalOperatorReturnsInvertedDefaultOptionsCodeFix), LanguageNames.CSharp),
+ [ExportCodeFixProvider(DiagnosticId.ConditionalOperatorReturnsInvertedDefaultOptions + "CF", LanguageNames.CSharp),
Shared]
public class ConditionalOperatorReturnsInvertedDefaultOptionsCodeFix : CodeFixProvider
{
@@ -47,7 +48,7 @@ private Task RemoveConditionalAsync(Document document, SyntaxNode root
}
var newRoot =
- root.ReplaceNode(conditionalExpression, newExpression).WithAdditionalAnnotations(Formatter.Annotation);
+ root.ReplaceNode(conditionalExpression, newExpression.WithAdditionalAnnotations(Formatter.Annotation));
var newDocument = document.WithSyntaxRoot(newRoot);
return Task.FromResult(newDocument.Project.Solution);
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ElementaryMethodsOfTypeInCollectionNotOverridden/ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ElementaryMethodsOfTypeInCollectionNotOverridden/ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer.cs
new file mode 100644
index 0000000..8c1cc4f
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ElementaryMethodsOfTypeInCollectionNotOverridden/ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer.cs
@@ -0,0 +1,86 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.General.ElementaryMethodsOfTypeInCollectionNotOverridden
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzer : DiagnosticAnalyzer
+ {
+ private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
+ private static readonly string Category = VSDiagnosticsResources.GeneralCategory;
+ private static readonly string Message = VSDiagnosticsResources.ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzerMessage;
+ private static readonly string Title = VSDiagnosticsResources.ElementaryMethodsOfTypeInCollectionNotOverriddenAnalyzerTitle;
+
+ internal static DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId.ElementaryMethodsOfTypeInCollectionNotOverridden, Title, Message, Category, Severity, true);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.ObjectCreationExpression);
+
+ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
+ {
+ var objectTypeInfo = context.SemanticModel.GetTypeInfo(context.Node).Type as INamedTypeSymbol;
+
+ if (objectTypeInfo == null)
+ {
+ return;
+ }
+
+ var ienumerableIsImplemented = objectTypeInfo.ImplementsInterface(typeof(IEnumerable)) ||
+ objectTypeInfo.ImplementsInterface(typeof(IEnumerable<>));
+
+ if (!ienumerableIsImplemented)
+ {
+ return;
+ }
+
+ var objectType = ((ObjectCreationExpressionSyntax) context.Node).Type as GenericNameSyntax;
+ if (objectType == null)
+ {
+ return;
+ }
+
+ foreach (var genericType in objectType.TypeArgumentList.Arguments)
+ {
+ if (genericType == null)
+ {
+ return;
+ }
+
+ var genericTypeInfo = context.SemanticModel.GetTypeInfo(genericType).Type;
+ if (genericTypeInfo == null ||
+ genericTypeInfo.TypeKind == TypeKind.Interface ||
+ genericTypeInfo.TypeKind == TypeKind.TypeParameter)
+ {
+ return;
+ }
+
+ var implementsEquals = false;
+ var implementsGetHashCode = false;
+ foreach (var member in genericTypeInfo.GetMembers())
+ {
+ if (member.Name == nameof(Equals))
+ {
+ implementsEquals = true;
+ }
+
+ if (member.Name == nameof(GetHashCode))
+ {
+ implementsGetHashCode = true;
+ }
+ }
+
+ if (!implementsEquals || !implementsGetHashCode)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule, genericType.GetLocation()));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/EqualsAndGetHashcodeNotImplementedTogether/EqualsAndGetHashcodeNotImplementedTogetherAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/EqualsAndGetHashcodeNotImplementedTogether/EqualsAndGetHashcodeNotImplementedTogetherAnalyzer.cs
new file mode 100644
index 0000000..6491c21
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/EqualsAndGetHashcodeNotImplementedTogether/EqualsAndGetHashcodeNotImplementedTogetherAnalyzer.cs
@@ -0,0 +1,101 @@
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.General.EqualsAndGetHashcodeNotImplementedTogether
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class EqualsAndGetHashcodeNotImplementedTogetherAnalyzer : DiagnosticAnalyzer
+ {
+ private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
+ private static readonly string Category = VSDiagnosticsResources.GeneralCategory;
+ private static readonly string Message = VSDiagnosticsResources.EqualsAndGetHashcodeNotImplementedTogetherAnalyzerMessage;
+ private static readonly string Title = VSDiagnosticsResources.EqualsAndGetHashcodeNotImplementedTogetherAnalyzerTitle;
+
+ internal static DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId.EqualsAndGetHashcodeNotImplementedTogether, Title, Message, Category, Severity, true);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+
+ public override void Initialize(AnalysisContext context) => context.RegisterCompilationStartAction((compilationContext) =>
+ {
+ var objectSymbol = compilationContext.Compilation.GetSpecialType(SpecialType.System_Object);
+ IMethodSymbol objectEquals = null;
+ IMethodSymbol objectGetHashCode = null;
+
+ foreach (var symbol in objectSymbol.GetMembers())
+ {
+ if (!(symbol is IMethodSymbol))
+ {
+ continue;
+ }
+
+ var method = (IMethodSymbol)symbol;
+ if (method.MetadataName == nameof(Equals) && method.Parameters.Length == 1)
+ {
+ objectEquals = method;
+ }
+
+ if (method.MetadataName == nameof(GetHashCode) && !method.Parameters.Any())
+ {
+ objectGetHashCode = method;
+ }
+ }
+
+ compilationContext.RegisterSyntaxNodeAction((syntaxNodeContext) =>
+ {
+ var classDeclaration = (ClassDeclarationSyntax) syntaxNodeContext.Node;
+
+ var equalsImplemented = false;
+ var getHashcodeImplemented = false;
+
+ foreach (var node in classDeclaration.Members)
+ {
+ if (!node.IsKind(SyntaxKind.MethodDeclaration))
+ {
+ continue;
+ }
+
+ var methodDeclaration = (MethodDeclarationSyntax)node;
+ if (!methodDeclaration.Modifiers.Contains(SyntaxKind.OverrideKeyword))
+ {
+ continue;
+ }
+
+ var methodSymbol = syntaxNodeContext.SemanticModel.GetDeclaredSymbol(methodDeclaration).OverriddenMethod;
+
+ // this will happen if the base class is deleted and there is still a derived class
+ if (methodSymbol == null)
+ {
+ return;
+ }
+
+ while (methodSymbol.IsOverride)
+ {
+ methodSymbol = methodSymbol.OverriddenMethod;
+ }
+
+ if (methodSymbol == objectEquals)
+ {
+ equalsImplemented = true;
+ }
+
+ if (methodSymbol == objectGetHashCode)
+ {
+ getHashcodeImplemented = true;
+ }
+ }
+
+ if (equalsImplemented ^ getHashcodeImplemented)
+ {
+ syntaxNodeContext.ReportDiagnostic(Diagnostic.Create(Rule, classDeclaration.Identifier.GetLocation(),
+ ImmutableDictionary.CreateRange(new[] { new KeyValuePair("IsEqualsImplemented", equalsImplemented.ToString()) })));
+ }
+ }, SyntaxKind.ClassDeclaration);
+ });
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/EqualsAndGetHashcodeNotImplementedTogether/EqualsAndGetHashcodeNotImplementedTogetherCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/EqualsAndGetHashcodeNotImplementedTogether/EqualsAndGetHashcodeNotImplementedTogetherCodeFix.cs
new file mode 100644
index 0000000..dfffd83
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/EqualsAndGetHashcodeNotImplementedTogether/EqualsAndGetHashcodeNotImplementedTogetherCodeFix.cs
@@ -0,0 +1,96 @@
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Formatting;
+using Microsoft.CodeAnalysis.Simplification;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.General.EqualsAndGetHashcodeNotImplementedTogether
+{
+ [ExportCodeFixProvider(DiagnosticId.EqualsAndGetHashcodeNotImplementedTogether + "CF", LanguageNames.CSharp), Shared]
+ public class EqualsAndGetHashcodeNotImplementedTogetherCodeFix : CodeFixProvider
+ {
+ public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(EqualsAndGetHashcodeNotImplementedTogetherAnalyzer.Rule.Id);
+
+ public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
+
+ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+ var diagnostic = context.Diagnostics.First();
+ var diagnosticSpan = diagnostic.Location.SourceSpan;
+
+ var statement = root.FindNode(diagnosticSpan);
+
+ if (bool.Parse(diagnostic.Properties["IsEqualsImplemented"]))
+ {
+ context.RegisterCodeFix(
+ CodeAction.Create(string.Format(VSDiagnosticsResources.EqualsAndGetHashcodeNotImplementedTogetherCodeFixTitle, "GetHashCode()"),
+ x => ImplementGetHashCodeAsync(context.Document, root, statement),
+ EqualsAndGetHashcodeNotImplementedTogetherAnalyzer.Rule.Id),
+ diagnostic);
+ }
+ else
+ {
+ context.RegisterCodeFix(
+ CodeAction.Create(string.Format(VSDiagnosticsResources.EqualsAndGetHashcodeNotImplementedTogetherCodeFixTitle, "Equals(object obj)"),
+ x => ImplementEqualsAsync(context.Document, root, statement),
+ EqualsAndGetHashcodeNotImplementedTogetherAnalyzer.Rule.Id),
+ diagnostic);
+ }
+ }
+
+ private async Task ImplementEqualsAsync(Document document, SyntaxNode root, SyntaxNode statement)
+ {
+ var classDeclaration = (ClassDeclarationSyntax) statement;
+
+ var newRoot = root.ReplaceNode(classDeclaration, classDeclaration.AddMembers(GetEqualsMethod()));
+ var newDocument = await Simplifier.ReduceAsync(document.WithSyntaxRoot(newRoot));
+ return newDocument.Project.Solution;
+ }
+
+ private async Task ImplementGetHashCodeAsync(Document document, SyntaxNode root, SyntaxNode statement)
+ {
+ var classDeclaration = (ClassDeclarationSyntax)statement;
+
+ var newRoot = root.ReplaceNode(classDeclaration, classDeclaration.AddMembers(GetGetHashCodeMethod()));
+ var newDocument = await Simplifier.ReduceAsync(document.WithSyntaxRoot(newRoot));
+ return newDocument.Project.Solution;
+ }
+
+ private MethodDeclarationSyntax GetEqualsMethod()
+ {
+ var publicModifier = SyntaxFactory.Token(SyntaxKind.PublicKeyword);
+ var overrideModifier = SyntaxFactory.Token(SyntaxKind.OverrideKeyword);
+ var bodyStatement = SyntaxFactory.ParseStatement("throw new System.NotImplementedException();")
+ .WithAdditionalAnnotations(Simplifier.Annotation);
+ var parameter = SyntaxFactory.Parameter(SyntaxFactory.Identifier("obj"))
+ .WithType(SyntaxFactory.ParseTypeName("object"));
+
+ return SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("bool"), "Equals")
+ .AddModifiers(publicModifier, overrideModifier)
+ .AddBodyStatements(bodyStatement)
+ .AddParameterListParameters(parameter)
+ .WithAdditionalAnnotations(Formatter.Annotation);
+ }
+
+ private MethodDeclarationSyntax GetGetHashCodeMethod()
+ {
+ var publicModifier = SyntaxFactory.Token(SyntaxKind.PublicKeyword);
+ var overrideModifier = SyntaxFactory.Token(SyntaxKind.OverrideKeyword);
+ var bodyStatement = SyntaxFactory.ParseStatement("throw new System.NotImplementedException();")
+ .WithAdditionalAnnotations(Simplifier.Annotation);
+
+ return SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("int"), "GetHashCode")
+ .AddModifiers(publicModifier, overrideModifier)
+ .AddBodyStatements(bodyStatement)
+ .WithAdditionalAnnotations(Formatter.Annotation);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ExplicitAccessModifiers/ExplicitAccessModifiersAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ExplicitAccessModifiers/ExplicitAccessModifiersAnalyzer.cs
index d95ab4e..5ab6700 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ExplicitAccessModifiers/ExplicitAccessModifiersAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ExplicitAccessModifiers/ExplicitAccessModifiersAnalyzer.cs
@@ -1,5 +1,4 @@
using System.Collections.Immutable;
-using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -12,203 +11,194 @@ namespace VSDiagnostics.Diagnostics.General.ExplicitAccessModifiers
internal class ExplicitAccessModifiersAnalyzer : DiagnosticAnalyzer
{
private const DiagnosticSeverity Severity = DiagnosticSeverity.Hidden;
-
private static readonly string Category = VSDiagnosticsResources.GeneralCategory;
private static readonly string Message = VSDiagnosticsResources.ExplicitAccessModifiersAnalyzerMessage;
private static readonly string Title = VSDiagnosticsResources.ExplicitAccessModifiersAnalyzerTitle;
- internal static DiagnosticDescriptor Rule
- => new DiagnosticDescriptor(DiagnosticId.ExplicitAccessModifiers, Title, Message, Category, Severity, true);
+ private readonly SyntaxKind[] _accessModifierKinds =
+ {
+ SyntaxKind.PublicKeyword,
+ SyntaxKind.ProtectedKeyword,
+ SyntaxKind.InternalKeyword,
+ SyntaxKind.PrivateKeyword
+ };
+
+ internal static DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId.ExplicitAccessModifiers, Title, Message, Category, Severity, true);
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
- context.RegisterSyntaxNodeAction(AnalyzeSymbol,
- SyntaxKind.ClassDeclaration,
- SyntaxKind.ConstructorDeclaration,
- SyntaxKind.DelegateDeclaration,
- SyntaxKind.EnumDeclaration,
- SyntaxKind.EventDeclaration,
- SyntaxKind.EventFieldDeclaration,
- SyntaxKind.FieldDeclaration,
- SyntaxKind.IndexerDeclaration,
- SyntaxKind.InterfaceDeclaration,
- SyntaxKind.MethodDeclaration,
- SyntaxKind.PropertyDeclaration,
- SyntaxKind.StructDeclaration);
+ context.RegisterSyntaxNodeAction(HandleClass, SyntaxKind.ClassDeclaration);
+ context.RegisterSyntaxNodeAction(HandleConstructor, SyntaxKind.ConstructorDeclaration);
+ context.RegisterSyntaxNodeAction(HandleDelegate, SyntaxKind.DelegateDeclaration);
+ context.RegisterSyntaxNodeAction(HandleEnum, SyntaxKind.EnumDeclaration);
+ context.RegisterSyntaxNodeAction(HandleEvent, SyntaxKind.EventDeclaration);
+ context.RegisterSyntaxNodeAction(HandleEventField, SyntaxKind.EventFieldDeclaration);
+ context.RegisterSyntaxNodeAction(HandleField, SyntaxKind.FieldDeclaration);
+ context.RegisterSyntaxNodeAction(HandleIndexer, SyntaxKind.IndexerDeclaration);
+ context.RegisterSyntaxNodeAction(HandleInterface, SyntaxKind.InterfaceDeclaration);
+ context.RegisterSyntaxNodeAction(HandleMethod, SyntaxKind.MethodDeclaration);
+ context.RegisterSyntaxNodeAction(HandleProperty, SyntaxKind.PropertyDeclaration);
+ context.RegisterSyntaxNodeAction(HandleStruct, SyntaxKind.StructDeclaration);
}
- private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
+ private void HandleClass(SyntaxNodeAnalysisContext context)
{
- if (context.Node.Parent is InterfaceDeclarationSyntax)
+ var declarationExpression = (ClassDeclarationSyntax) context.Node;
+ if (!declarationExpression.Modifiers.ContainsAny(_accessModifierKinds))
{
- return;
+ var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
+ context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
+ accessibility.ToString().ToLowerInvariant()));
}
+ }
- if (context.Node is ClassDeclarationSyntax)
+ private void HandleStruct(SyntaxNodeAnalysisContext context)
+ {
+ var declarationExpression = (StructDeclarationSyntax) context.Node;
+ if (!declarationExpression.Modifiers.ContainsAny(_accessModifierKinds))
{
- var declarationExpression = (ClassDeclarationSyntax) context.Node;
- if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())))
- {
- var accessibility =
- context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
- accessibility.ToString().ToLowerInvariant()));
- }
+ var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
+ context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
+ accessibility.ToString().ToLowerInvariant()));
}
+ }
- if (context.Node is StructDeclarationSyntax)
+ private void HandleEnum(SyntaxNodeAnalysisContext context)
+ {
+ var declarationExpression = (EnumDeclarationSyntax) context.Node;
+ if (!declarationExpression.Modifiers.ContainsAny(_accessModifierKinds))
{
- var declarationExpression = (StructDeclarationSyntax) context.Node;
- if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())))
- {
- var accessibility =
- context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
- accessibility.ToString().ToLowerInvariant()));
- }
+ var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
+ context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
+ accessibility.ToString().ToLowerInvariant()));
}
+ }
- if (context.Node is EnumDeclarationSyntax)
+ private void HandleDelegate(SyntaxNodeAnalysisContext context)
+ {
+ var declarationExpression = (DelegateDeclarationSyntax) context.Node;
+ if (!declarationExpression.Modifiers.ContainsAny(_accessModifierKinds))
{
- var declarationExpression = (EnumDeclarationSyntax) context.Node;
- if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())))
- {
- var accessibility =
- context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
- accessibility.ToString().ToLowerInvariant()));
- }
+ var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
+ context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
+ accessibility.ToString().ToLowerInvariant()));
}
+ }
- if (context.Node is DelegateDeclarationSyntax)
+ private void HandleInterface(SyntaxNodeAnalysisContext context)
+ {
+ var declarationExpression = (InterfaceDeclarationSyntax) context.Node;
+ if (!declarationExpression.Modifiers.ContainsAny(_accessModifierKinds))
{
- var declarationExpression = (DelegateDeclarationSyntax) context.Node;
- if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())))
- {
- var accessibility =
- context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
- accessibility.ToString().ToLowerInvariant()));
- }
+ var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
+ context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
+ accessibility.ToString().ToLowerInvariant()));
}
+ }
- if (context.Node is InterfaceDeclarationSyntax)
+ private void HandleField(SyntaxNodeAnalysisContext context)
+ {
+ var declarationExpression = (FieldDeclarationSyntax) context.Node;
+ if (!declarationExpression.Modifiers.ContainsAny(_accessModifierKinds))
{
- var declarationExpression = (InterfaceDeclarationSyntax) context.Node;
- if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())))
- {
- var accessibility =
- context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
- accessibility.ToString().ToLowerInvariant()));
- }
+ context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(), "private"));
}
+ }
- if (context.Node is FieldDeclarationSyntax)
+ private void HandleProperty(SyntaxNodeAnalysisContext context)
+ {
+ if (context.Node.Parent.IsKind(SyntaxKind.InterfaceDeclaration))
{
- var declarationExpression = (FieldDeclarationSyntax) context.Node;
- if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())))
- {
- context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
- "private"));
- }
+ return;
}
- if (context.Node is PropertyDeclarationSyntax)
+ var declarationExpression = (PropertyDeclarationSyntax) context.Node;
+ if (!declarationExpression.Modifiers.ContainsAny(_accessModifierKinds) &&
+ declarationExpression.ExplicitInterfaceSpecifier == null)
{
- var declarationExpression = (PropertyDeclarationSyntax) context.Node;
- if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())) &&
- declarationExpression.ExplicitInterfaceSpecifier == null)
- {
- var accessibility =
- context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
- accessibility.ToString().ToLowerInvariant()));
- }
+ var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
+ context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
+ accessibility.ToString().ToLowerInvariant()));
}
+ }
- if (context.Node is MethodDeclarationSyntax)
+ private void HandleMethod(SyntaxNodeAnalysisContext context)
+ {
+ if (context.Node.Parent.IsKind(SyntaxKind.InterfaceDeclaration))
{
- var declarationExpression = (MethodDeclarationSyntax) context.Node;
- if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())) &&
- declarationExpression.Modifiers.All(m => m.Kind() != SyntaxKind.PartialKeyword) &&
- declarationExpression.ExplicitInterfaceSpecifier == null)
- {
- var accessibility =
- context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
- accessibility.ToString().ToLowerInvariant()));
- }
+ return;
}
- if (context.Node is ConstructorDeclarationSyntax)
+ var declarationExpression = (MethodDeclarationSyntax) context.Node;
+ if (!declarationExpression.Modifiers.ContainsAny(_accessModifierKinds) &&
+ !declarationExpression.Modifiers.Contains(SyntaxKind.PartialKeyword) &&
+ declarationExpression.ExplicitInterfaceSpecifier == null)
{
- var declarationExpression = (ConstructorDeclarationSyntax) context.Node;
- if (
- !declarationExpression.Modifiers.Any(
- m => _accessModifierKinds.Contains(m.Kind()) || m.Kind() == SyntaxKind.StaticKeyword))
- {
- var accessibility =
- context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
- accessibility.ToString().ToLowerInvariant()));
- }
+ var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
+ context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
+ accessibility.ToString().ToLowerInvariant()));
}
+ }
- if (context.Node is EventFieldDeclarationSyntax)
+ private void HandleConstructor(SyntaxNodeAnalysisContext context)
+ {
+ var declarationExpression = (ConstructorDeclarationSyntax) context.Node;
+ if (!declarationExpression.Modifiers.ContainsAny(_accessModifierKinds) &&
+ !declarationExpression.Modifiers.Contains(SyntaxKind.StaticKeyword))
{
- var declarationExpression = (EventFieldDeclarationSyntax) context.Node;
- if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())))
- {
- context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
- "private"));
- }
+ var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
+ context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
+ accessibility.ToString().ToLowerInvariant()));
}
+ }
- if (context.Node is EventDeclarationSyntax)
+ private void HandleEventField(SyntaxNodeAnalysisContext context)
+ {
+ if (context.Node.Parent.IsKind(SyntaxKind.InterfaceDeclaration))
{
- var declarationExpression = (EventDeclarationSyntax) context.Node;
- if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())))
- {
- var accessibility =
- context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
+ return;
+ }
- context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
- accessibility.ToString().ToLowerInvariant()));
- }
+ var declarationExpression = (EventFieldDeclarationSyntax) context.Node;
+ if (!declarationExpression.Modifiers.ContainsAny(_accessModifierKinds))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(), "private"));
}
+ }
- if (context.Node is IndexerDeclarationSyntax)
+ private void HandleEvent(SyntaxNodeAnalysisContext context)
+ {
+ if (context.Node.Parent.IsKind(SyntaxKind.InterfaceDeclaration))
{
- var declarationExpression = (IndexerDeclarationSyntax) context.Node;
- if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())) &&
- declarationExpression.ExplicitInterfaceSpecifier == null)
- {
- var accessibility =
- context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
+ return;
+ }
- context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
- accessibility.ToString().ToLowerInvariant()));
- }
+ var declarationExpression = (EventDeclarationSyntax) context.Node;
+ if (!declarationExpression.Modifiers.ContainsAny(_accessModifierKinds))
+ {
+ var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
+ context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
+ accessibility.ToString().ToLowerInvariant()));
}
}
- private readonly SyntaxKind[] _accessModifierKinds =
+ private void HandleIndexer(SyntaxNodeAnalysisContext context)
{
- SyntaxKind.PublicKeyword,
- SyntaxKind.ProtectedKeyword,
- SyntaxKind.InternalKeyword,
- SyntaxKind.PrivateKeyword
- };
+ if (context.Node.Parent.IsKind(SyntaxKind.InterfaceDeclaration))
+ {
+ return;
+ }
+
+ var declarationExpression = (IndexerDeclarationSyntax) context.Node;
+ if (!declarationExpression.Modifiers.ContainsAny(_accessModifierKinds) &&
+ declarationExpression.ExplicitInterfaceSpecifier == null)
+ {
+ var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
+ context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
+ accessibility.ToString().ToLowerInvariant()));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ExplicitAccessModifiers/ExplicitAccessModifiersCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ExplicitAccessModifiers/ExplicitAccessModifiersCodeFix.cs
index 0cc597a..3bb0b30 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ExplicitAccessModifiers/ExplicitAccessModifiersCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ExplicitAccessModifiers/ExplicitAccessModifiersCodeFix.cs
@@ -6,10 +6,11 @@
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Editing;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.General.ExplicitAccessModifiers
{
- [ExportCodeFixProvider(nameof(ExplicitAccessModifiersCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.ExplicitAccessModifiers + "CF", LanguageNames.CSharp), Shared]
public class ExplicitAccessModifiersCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds
@@ -31,12 +32,12 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
context.RegisterCodeFix(
CodeAction.Create(VSDiagnosticsResources.ExplicitAccessModifiersCodeFixTitle,
- x => AddModifier(context.Document, root, statement, accessibility),
+ x => AddModifierAsync(context.Document, root, statement, accessibility),
ExplicitAccessModifiersAnalyzer.Rule.Id), diagnostic);
}
- private Task AddModifier(Document document, SyntaxNode root, SyntaxNode statement,
- Accessibility accessibility)
+ private Task AddModifierAsync(Document document, SyntaxNode root, SyntaxNode statement,
+ Accessibility accessibility)
{
var generator = SyntaxGenerator.GetGenerator(document);
var newStatement = generator.WithAccessibility(statement, accessibility);
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/GetHashCodeRefersToMutableMember/GetHashCodeRefersToMutableMemberAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/GetHashCodeRefersToMutableMember/GetHashCodeRefersToMutableMemberAnalyzer.cs
new file mode 100644
index 0000000..2c70075
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/GetHashCodeRefersToMutableMember/GetHashCodeRefersToMutableMemberAnalyzer.cs
@@ -0,0 +1,173 @@
+using System;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using VSDiagnostics.Utilities;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace VSDiagnostics.Diagnostics.General.GetHashCodeRefersToMutableMember
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class GetHashCodeRefersToMutableMemberAnalyzer : DiagnosticAnalyzer
+ {
+ private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
+
+ private static readonly string Category = VSDiagnosticsResources.GeneralCategory;
+ private static readonly string Message = VSDiagnosticsResources.GetHashCodeRefersToMutableFieldAnalyzerMessage;
+ private static readonly string Title = VSDiagnosticsResources.GetHashCodeRefersToMutableFieldAnalyzerTitle;
+
+ internal static DiagnosticDescriptor Rule =>
+ new DiagnosticDescriptor(DiagnosticId.GetHashCodeRefersToMutableField, Title, Message, Category, Severity, true);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+
+ public override void Initialize(AnalysisContext context) =>
+ context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
+
+ private void AnalyzeSymbol(SymbolAnalysisContext context)
+ {
+ var namedType = (INamedTypeSymbol)context.Symbol;
+ var semanticModel = context.Compilation.GetSemanticModel(context.Symbol.Locations[0].SourceTree);
+
+ var getHashCode = GetHashCodeSymbol(namedType);
+ if (getHashCode == null) { return; }
+
+ var getHashCodeLocation = getHashCode.Locations[0];
+ var root = getHashCodeLocation?.SourceTree.GetRoot(context.CancellationToken);
+ if (root == null)
+ {
+ return;
+ }
+
+ var getHashCodeNode = (MethodDeclarationSyntax)root.FindNode(getHashCodeLocation.SourceSpan);
+ var nodes = getHashCodeNode.DescendantNodes(descendIntoChildren: target => true);
+
+ var identifierNameNodes = nodes.OfType(SyntaxKind.IdentifierName);
+ foreach (var node in identifierNameNodes)
+ {
+ var symbol = semanticModel.GetSymbolInfo(node).Symbol;
+ if (symbol == null)
+ {
+ continue;
+ }
+
+ if (symbol.Kind == SymbolKind.Field)
+ {
+ var fieldIsMutableOrStatic = FieldIsMutableOrStatic((IFieldSymbol) symbol);
+ if (fieldIsMutableOrStatic.Item1)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule, getHashCode.Locations[0],
+ fieldIsMutableOrStatic.Item2));
+ }
+ }
+ else if (symbol.Kind == SymbolKind.Property)
+ {
+ var propertyIsMutable = PropertyIsMutable((IPropertySymbol) symbol, root);
+ if (propertyIsMutable.Item1)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule, getHashCode.Locations[0],
+ propertyIsMutable.Item2));
+ }
+ }
+ }
+ }
+
+ private IMethodSymbol GetHashCodeSymbol(INamedTypeSymbol symbol)
+ {
+ foreach (var member in symbol.GetMembers())
+ {
+ if (!(member is IMethodSymbol))
+ {
+ continue;
+ }
+
+ var method = (IMethodSymbol)member;
+ if (method.MetadataName == nameof(GetHashCode) && method.Parameters.Length == 0)
+ {
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ private Tuple FieldIsMutableOrStatic(IFieldSymbol field)
+ {
+ var description = string.Empty;
+ var returnResult = false;
+
+ if (field.IsConst)
+ {
+ description += "const ";
+ returnResult = true;
+ }
+
+ // constant fields are marked static
+ if (field.IsStatic && !field.IsConst)
+ {
+ description += "static ";
+ returnResult = true;
+ }
+
+ // constant fields are marked non-readonly
+ if (!field.IsReadOnly && !field.IsConst)
+ {
+ description += "non-readonly ";
+ returnResult = true;
+ }
+
+ if (!field.Type.IsValueType && field.Type.SpecialType != SpecialType.System_String)
+ {
+ description += "non-value type, non-string ";
+ returnResult = true;
+ }
+
+ return Tuple.Create(returnResult, description + "field " + field.Name);
+ }
+
+ private Tuple PropertyIsMutable(IPropertySymbol property, SyntaxNode root)
+ {
+ var description = string.Empty;
+ var returnResult = false;
+
+ if (property.IsStatic)
+ {
+ description += "static ";
+ returnResult = true;
+ }
+
+ if (!property.Type.IsValueType && property.Type.SpecialType != SpecialType.System_String)
+ {
+ description += "non-value type, non-string ";
+ returnResult = true;
+ }
+
+ if (property.SetMethod != null)
+ {
+ description += "settable ";
+ returnResult = true;
+ }
+
+ var propertyLocation = property.Locations[0];
+ var propertyNode = (PropertyDeclarationSyntax) root.FindNode(propertyLocation.SourceSpan);
+
+ // ensure getter does not have body
+ // the property has to have at least one of {get, set}, and it doesn't have a set (see above)
+ // this will not have an NRE in First()
+ // the accessor list might be null if it uses the arrow operator `=>`
+ if (propertyNode.AccessorList == null ||
+ propertyNode.AccessorList.Accessors[0].Body != null)
+ {
+ description += "property with bodied getter ";
+ returnResult = true;
+ }
+ else
+ {
+ description += "property ";
+ }
+
+ return Tuple.Create(returnResult, description + property.Name);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/GotoDetection/GotoDetectionAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/GotoDetection/GotoDetectionAnalyzer.cs
index ad5e9c8..f921cd0 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/GotoDetection/GotoDetectionAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/GotoDetection/GotoDetectionAnalyzer.cs
@@ -8,7 +8,7 @@
namespace VSDiagnostics.Diagnostics.General.GotoDetection
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
- internal class GotoDetectionAnalyzer : DiagnosticAnalyzer
+ public class GotoDetectionAnalyzer : DiagnosticAnalyzer
{
private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
@@ -21,19 +21,12 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.GotoStatement, SyntaxKind.GotoCaseStatement,
- SyntaxKind.GotoDefaultStatement);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.GotoStatement, SyntaxKind.GotoCaseStatement,
+ SyntaxKind.GotoDefaultStatement);
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
- var literalExpression = context.Node as GotoStatementSyntax;
- if (literalExpression == null)
- {
- return;
- }
+ var literalExpression = (GotoStatementSyntax) context.Node;
context.ReportDiagnostic(Diagnostic.Create(Rule, literalExpression.GetLocation()));
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/IfStatementWithoutBraces/IfStatementWithoutBracesAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/IfStatementWithoutBraces/IfStatementWithoutBracesAnalyzer.cs
deleted file mode 100644
index 69edf21..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/IfStatementWithoutBraces/IfStatementWithoutBracesAnalyzer.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using System.Collections.Immutable;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Diagnostics;
-using VSDiagnostics.Utilities;
-
-namespace VSDiagnostics.Diagnostics.General.IfStatementWithoutBraces
-{
- [DiagnosticAnalyzer(LanguageNames.CSharp)]
- public class IfStatementWithoutBracesAnalyzer : DiagnosticAnalyzer
- {
- private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
-
- private static readonly string Category = VSDiagnosticsResources.GeneralCategory;
- private static readonly string Message = VSDiagnosticsResources.IfStatementWithoutBracesAnalyzerMessage;
- private static readonly string Title = VSDiagnosticsResources.IfStatementWithoutBracesAnalyzerTitle;
-
- internal static DiagnosticDescriptor Rule
- => new DiagnosticDescriptor(DiagnosticId.IfStatementWithoutBraces, Title, Message, Category, Severity, true);
-
- public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
-
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.IfStatement, SyntaxKind.ElseClause);
- }
-
- private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
- {
- var ifStatement = context.Node as IfStatementSyntax;
- if (ifStatement != null)
- {
- HandleIf(context, ifStatement);
- }
-
- var elseClause = context.Node as ElseClauseSyntax;
- if (elseClause != null)
- {
- HandleElse(context, elseClause);
- }
- }
-
- private void HandleIf(SyntaxNodeAnalysisContext context, IfStatementSyntax ifStatement)
- {
- if (ifStatement.Statement is BlockSyntax)
- {
- return;
- }
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, ifStatement.IfKeyword.GetLocation()));
- }
-
- private void HandleElse(SyntaxNodeAnalysisContext context, ElseClauseSyntax elseClause)
- {
- if (elseClause.Statement is BlockSyntax)
- {
- return;
- }
-
- if (elseClause.Statement is IfStatementSyntax)
- {
- return;
- }
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, elseClause.ElseKeyword.GetLocation()));
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/IfStatementWithoutBraces/IfStatementWithoutBracesCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/IfStatementWithoutBraces/IfStatementWithoutBracesCodeFix.cs
deleted file mode 100644
index 15c51bb..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/IfStatementWithoutBraces/IfStatementWithoutBracesCodeFix.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System.Collections.Immutable;
-using System.Composition;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CodeActions;
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-
-namespace VSDiagnostics.Diagnostics.General.IfStatementWithoutBraces
-{
- [ExportCodeFixProvider(nameof(IfStatementWithoutBracesCodeFix), LanguageNames.CSharp), Shared]
- public class IfStatementWithoutBracesCodeFix : CodeFixProvider
- {
- public override ImmutableArray FixableDiagnosticIds
- => ImmutableArray.Create(IfStatementWithoutBracesAnalyzer.Rule.Id);
-
- public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
-
- public override async Task RegisterCodeFixesAsync(CodeFixContext context)
- {
- var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
- var diagnostic = context.Diagnostics.First();
- var diagnosticSpan = diagnostic.Location.SourceSpan;
-
- var statement = root.FindNode(diagnosticSpan);
- context.RegisterCodeFix(
- CodeAction.Create(VSDiagnosticsResources.IfStatementWithoutBracesCodeFixTitle,
- x => UseBracesNotationAsync(context.Document, root, statement),
- IfStatementWithoutBracesAnalyzer.Rule.Id), diagnostic);
- }
-
- private Task UseBracesNotationAsync(Document document, SyntaxNode root, SyntaxNode statement)
- {
- SyntaxNode newBlock = null;
-
- var ifSyntax = statement as IfStatementSyntax;
- if (ifSyntax != null)
- {
- newBlock = GetNewBlock(statement, ifSyntax.Statement);
- }
-
- var elseSyntax = statement as ElseClauseSyntax;
- if (elseSyntax != null)
- {
- newBlock = GetNewBlock(statement, elseSyntax.Statement);
- }
-
- var newRoot = root.ReplaceNode(statement, newBlock);
- var newDocument = document.WithSyntaxRoot(newRoot);
- return Task.FromResult(newDocument.Project.Solution);
- }
-
- private SyntaxNode GetNewBlock(SyntaxNode statement, StatementSyntax statementBody)
- {
- var body = SyntaxFactory.Block(statementBody);
- return statement.ReplaceNode(statementBody, body);
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ImplementEqualsAndGetHashCode/ImplementEqualsAndGetHashCodeAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ImplementEqualsAndGetHashCode/ImplementEqualsAndGetHashCodeAnalyzer.cs
new file mode 100644
index 0000000..36feb51
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ImplementEqualsAndGetHashCode/ImplementEqualsAndGetHashCodeAnalyzer.cs
@@ -0,0 +1,100 @@
+using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.General.ImplementEqualsAndGetHashCode
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class ImplementEqualsAndGetHashCodeAnalyzer : DiagnosticAnalyzer
+ {
+ private const DiagnosticSeverity Severity = DiagnosticSeverity.Hidden;
+
+ private static readonly string Category = VSDiagnosticsResources.GeneralCategory;
+ private static readonly string Message = VSDiagnosticsResources.ImplementEqualsAndGetHashCodeAnalyzerMessage;
+ private static readonly string Title = VSDiagnosticsResources.ImplementEqualsAndGetHashCodeAnalyzerTitle;
+
+ internal static DiagnosticDescriptor Rule =>
+ new DiagnosticDescriptor(DiagnosticId.ImplementEqualsAndGetHashCode, Title, Message, Category, Severity, true);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+
+ public override void Initialize(AnalysisContext context) =>
+ context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
+
+ private void AnalyzeSymbol(SymbolAnalysisContext symbol)
+ {
+ IMethodSymbol objectEquals;
+ IMethodSymbol objectGetHashCode;
+
+ var namedType = (INamedTypeSymbol)symbol.Symbol;
+ GetEqualsAndGetHashCodeSymbols(namedType, out objectEquals, out objectGetHashCode);
+
+ if (objectEquals != null || objectGetHashCode != null) { return; }
+
+ if (MembersContainNonStaticFieldOrProperty(namedType.GetMembers()))
+ {
+ for (var i = 0; i < namedType.Locations.Count(); i++)
+ {
+ symbol.ReportDiagnostic(Diagnostic.Create(Rule, namedType.Locations[i],
+ namedType.TypeKind == TypeKind.Class ? "Class" : "Struct", namedType.Name));
+ }
+ }
+ }
+
+ private void GetEqualsAndGetHashCodeSymbols(INamedTypeSymbol symbol, out IMethodSymbol equalsSymbol, out IMethodSymbol getHashCodeSymbol)
+ {
+ equalsSymbol = null;
+ getHashCodeSymbol = null;
+
+ foreach (var member in symbol.GetMembers())
+ {
+ if (!(member is IMethodSymbol))
+ {
+ continue;
+ }
+
+ var method = (IMethodSymbol)member;
+ if (method.MetadataName == nameof(Equals) && method.Parameters.Count() == 1)
+ {
+ equalsSymbol = method;
+ }
+
+ if (method.MetadataName == nameof(GetHashCode) && !method.Parameters.Any())
+ {
+ getHashCodeSymbol = method;
+ }
+ }
+ }
+
+ private bool MembersContainNonStaticFieldOrProperty(ImmutableArray members)
+ {
+ foreach (var member in members)
+ {
+ if (member.Kind != SymbolKind.Field && member.Kind != SymbolKind.Property)
+ {
+ continue;
+ }
+
+ if (member.IsStatic)
+ {
+ continue;
+ }
+
+ if (member.Kind == SymbolKind.Field)
+ {
+ return true;
+ }
+
+ var property = (IPropertySymbol) member;
+ if (property.GetMethod != null)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ImplementEqualsAndGetHashCode/ImplementEqualsAndGetHashCodeCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ImplementEqualsAndGetHashCode/ImplementEqualsAndGetHashCodeCodeFix.cs
new file mode 100644
index 0000000..8d9e9dc
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/ImplementEqualsAndGetHashCode/ImplementEqualsAndGetHashCodeCodeFix.cs
@@ -0,0 +1,292 @@
+using System;
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Formatting;
+using VSDiagnostics.Utilities;
+using System.Collections.Generic;
+
+namespace VSDiagnostics.Diagnostics.General.ImplementEqualsAndGetHashCode
+{
+ [ExportCodeFixProvider(DiagnosticId.ImplementEqualsAndGetHashCode + "CF", LanguageNames.CSharp), Shared]
+ public class ImplementEqualsAndGetHashCodeCodeFix : CodeFixProvider
+ {
+ public override ImmutableArray FixableDiagnosticIds
+ => ImmutableArray.Create(ImplementEqualsAndGetHashCodeAnalyzer.Rule.Id);
+
+ public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
+
+ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+ var diagnostic = context.Diagnostics.First();
+ var diagnosticSpan = diagnostic.Location.SourceSpan;
+
+ var statement = root.FindNode(diagnosticSpan);
+
+ context.RegisterCodeFix(
+ CodeAction.Create(string.Format(VSDiagnosticsResources.ImplementEqualsAndGetHashCodeCodeFixTitle),
+ x => ImplementEqualsAndGetHashCodeAsync(context.Document, root, statement),
+ ImplementEqualsAndGetHashCodeAnalyzer.Rule.Id),
+ diagnostic);
+ }
+
+ private async Task ImplementEqualsAndGetHashCodeAsync(Document document, SyntaxNode root, SyntaxNode declaration)
+ {
+ var model = await document.GetSemanticModelAsync();
+
+ var objectSymbol = model.Compilation.GetSpecialType(SpecialType.System_Object);
+ var objectEquals = objectSymbol.GetMembers().OfType()
+ .Single(method => method.MetadataName == nameof(Equals) && method.Parameters.Count() == 1);
+
+ var typeDeclaration = (TypeDeclarationSyntax) declaration;
+ var typeSymbol = model.GetDeclaredSymbol(typeDeclaration);
+
+ var equalsMethod = GetEqualsMethod(typeDeclaration.Identifier, typeSymbol.GetMembers(), typeSymbol, objectEquals);
+ var getHashCodeMethod = GetGetHashCodeMethod(typeSymbol.GetMembers());
+
+ var newNode = declaration.IsKind(SyntaxKind.ClassDeclaration)
+ ? (TypeDeclarationSyntax)((ClassDeclarationSyntax)typeDeclaration).AddMembers(equalsMethod, getHashCodeMethod)
+ : (TypeDeclarationSyntax)((StructDeclarationSyntax)typeDeclaration).AddMembers(equalsMethod, getHashCodeMethod);
+
+ return document.WithSyntaxRoot(root.ReplaceNode(typeDeclaration, newNode));
+ }
+
+ private MethodDeclarationSyntax GetEqualsMethod(SyntaxToken identifier, ImmutableArray members, INamedTypeSymbol typeSymbol, IMethodSymbol objectEquals)
+ {
+ var publicModifier = SyntaxFactory.Token(SyntaxKind.PublicKeyword);
+ var overrideModifier = SyntaxFactory.Token(SyntaxKind.OverrideKeyword);
+
+ var parameter = SyntaxFactory.Parameter(SyntaxFactory.Identifier("obj"))
+ .WithType(SyntaxFactory.ParseTypeName("object"));
+
+ var ifStatement = SyntaxFactory.IfStatement(SyntaxFactory.ParseExpression($"obj == null || typeof({identifier}) != obj.GetType()"),
+ SyntaxFactory.Block(SyntaxFactory.ParseStatement("return false;")));
+
+ // the default formatting is a single space--we want a new line
+ var castStatement = SyntaxFactory.ParseStatement($"var value = ({identifier}) obj;{Environment.NewLine}");
+
+ var fieldAndPropertyEqualityStatements = new List();
+ foreach (var member in members)
+ {
+ var fieldEqualityStatement = GetFieldComparisonStatement(member);
+ if (!string.IsNullOrEmpty(fieldEqualityStatement))
+ {
+ fieldAndPropertyEqualityStatements.Add(fieldEqualityStatement);
+ }
+
+ var propertyEqualityStatement = GetPropertyComparisonStatement(member);
+ if (!string.IsNullOrEmpty(propertyEqualityStatement))
+ {
+ fieldAndPropertyEqualityStatements.Add(propertyEqualityStatement);
+ }
+ }
+
+ var symbolHasBaseTypeOverridingEquals = BaseClassImplementsEquals(objectEquals, typeSymbol);
+
+ var returnStatement = SyntaxFactory.ParseStatement(
+ $"return {(symbolHasBaseTypeOverridingEquals ? $"base.Equals(obj) &&{Environment.NewLine} " : string.Empty)}" +
+ string.Join($" &&{Environment.NewLine} ", fieldAndPropertyEqualityStatements) + ";");
+
+ return SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("bool"), "Equals")
+ .AddModifiers(publicModifier, overrideModifier)
+ .AddBodyStatements(ifStatement, castStatement, returnStatement)
+ .AddParameterListParameters(parameter)
+ .WithAdditionalAnnotations(Formatter.Annotation);
+ }
+
+ private string GetFieldComparisonStatement(ISymbol member)
+ {
+ if (member.Kind != SymbolKind.Field)
+ {
+ return string.Empty;
+ }
+
+ var field = (IFieldSymbol)member;
+ if (field.IsStatic || field.IsConst)
+ {
+ return string.Empty;
+ }
+
+ if (!field.DeclaringSyntaxReferences.Any())
+ {
+ return string.Empty;
+ }
+
+ return field.Type.IsValueType
+ ? $"{member.Name}.Equals(value.{member.Name})"
+ : $"{member.Name} == value.{member.Name}";
+ }
+
+ private string GetPropertyComparisonStatement(ISymbol member)
+ {
+ if (member.Kind != SymbolKind.Property)
+ {
+ return string.Empty;
+ }
+
+ var property = (IPropertySymbol)member;
+ if (property.IsStatic)
+ {
+ return string.Empty;
+ }
+
+ if (property.IsWriteOnly)
+ {
+ return string.Empty;
+ }
+
+ return property.Type.IsValueType
+ ? $"{property.Name}.Equals(value.{property.Name})"
+ : $"{property.Name} == value.{property.Name}";
+ }
+
+ private MethodDeclarationSyntax GetGetHashCodeMethod(ImmutableArray members)
+ {
+ var publicModifier = SyntaxFactory.Token(SyntaxKind.PublicKeyword);
+ var overrideModifier = SyntaxFactory.Token(SyntaxKind.OverrideKeyword);
+
+ var fieldAndPropertyGetHashCodeStatements = new List();
+ foreach (var member in members)
+ {
+ var fieldGetHashCodeStatement = GetFieldHashCodeStatements(member);
+ if (!string.IsNullOrEmpty(fieldGetHashCodeStatement))
+ {
+ fieldAndPropertyGetHashCodeStatements.Add(fieldGetHashCodeStatement);
+ }
+
+ var propertyGetHashCodeStatement = GetPropertyHashCodeStatement(member);
+ if (!string.IsNullOrEmpty(propertyGetHashCodeStatement))
+ {
+ fieldAndPropertyGetHashCodeStatements.Add(propertyGetHashCodeStatement);
+ }
+ }
+
+ if (!fieldAndPropertyGetHashCodeStatements.Any())
+ {
+ fieldAndPropertyGetHashCodeStatements.Add("base.GetHashCode()");
+ }
+
+ var returnStatement = SyntaxFactory.ParseStatement("return " +
+ string.Join($" ^{Environment.NewLine} ",
+ fieldAndPropertyGetHashCodeStatements) + ";")
+ .WithLeadingTrivia(
+ SyntaxFactory.ParseLeadingTrivia(
+@"// Add any fields you're interested in, taking into account the guidelines described in
+// https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.110%29.aspx
+"));
+
+ return SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("int"), "GetHashCode")
+ .AddModifiers(publicModifier, overrideModifier)
+ .AddBodyStatements(returnStatement)
+ .WithAdditionalAnnotations(Formatter.Annotation);
+ }
+
+ private string GetFieldHashCodeStatements(ISymbol member)
+ {
+ if (member.Kind != SymbolKind.Field)
+ {
+ return string.Empty;
+ }
+
+ var field = (IFieldSymbol) member;
+ if (field.IsStatic || field.IsConst)
+ {
+ return string.Empty;
+ }
+
+ if (!field.DeclaringSyntaxReferences.Any())
+ {
+ return string.Empty;
+ }
+
+ var symbol = field.Type;
+ if (!symbol.IsValueType && symbol.SpecialType != SpecialType.System_String)
+ {
+ return string.Empty;
+ }
+
+ if (field.IsReadOnly)
+ {
+ return $"{field.Name}.GetHashCode()";
+ }
+
+ return string.Empty;
+ }
+
+ private string GetPropertyHashCodeStatement(ISymbol member)
+ {
+ if (member.Kind != SymbolKind.Property)
+ {
+ return string.Empty;
+ }
+
+ var property = (IPropertySymbol)member;
+ if (property.IsStatic)
+ {
+ return string.Empty;
+ }
+
+ var symbol = property.Type;
+ if (!symbol.IsValueType && symbol.SpecialType != SpecialType.System_String)
+ {
+ return string.Empty;
+ }
+
+ if (!property.IsReadOnly)
+ {
+ return string.Empty;
+ }
+
+ var propertyNode = (PropertyDeclarationSyntax)property.DeclaringSyntaxReferences.First().GetSyntax();
+ if (propertyNode.AccessorList != null &&
+ propertyNode.AccessorList.Accessors.First(a => a.IsKind(SyntaxKind.GetAccessorDeclaration)).Body == null)
+ {
+ return $"{property.Name}.GetHashCode()";
+ }
+
+ return string.Empty;
+ }
+
+ private bool BaseClassImplementsEquals(IMethodSymbol objectEquals, INamedTypeSymbol symbol)
+ {
+ if (symbol.TypeKind != TypeKind.Class)
+ {
+ return false;
+ }
+
+ var baseType = symbol.BaseType;
+ if (baseType == null)
+ {
+ return false;
+ }
+
+ foreach (var member in baseType.GetMembers())
+ {
+ var method = member as IMethodSymbol;
+ if (method == null || !method.IsOverride)
+ {
+ continue;
+ }
+
+ while (method.IsOverride)
+ {
+ method = method.OverriddenMethod;
+ }
+
+ if (method == objectEquals)
+ {
+ return true;
+ }
+ }
+
+ return BaseClassImplementsEquals(objectEquals, baseType);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/LoopStatementWithoutBraces/LoopStatementWithoutBracesAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/LoopStatementWithoutBraces/LoopStatementWithoutBracesAnalyzer.cs
deleted file mode 100644
index 9ce75ba..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/LoopStatementWithoutBraces/LoopStatementWithoutBracesAnalyzer.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-using System.Collections.Immutable;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Diagnostics;
-using VSDiagnostics.Utilities;
-
-namespace VSDiagnostics.Diagnostics.General.LoopStatementWithoutBraces
-{
- [DiagnosticAnalyzer(LanguageNames.CSharp)]
- public class LoopStatementWithoutBracesAnalyzer : DiagnosticAnalyzer
- {
- private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
-
- private static readonly string Category = VSDiagnosticsResources.GeneralCategory;
- private static readonly string Message = VSDiagnosticsResources.LoopStatementWithoutBracesAnalyzerMessage;
- private static readonly string Title = VSDiagnosticsResources.LoopStatementWithoutBracesAnalyzerTitle;
-
- internal static DiagnosticDescriptor Rule
- => new DiagnosticDescriptor(DiagnosticId.LoopStatementWithoutBraces, Title, Message, Category, Severity, true);
-
- public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
-
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.ForStatement, SyntaxKind.ForEachStatement,
- SyntaxKind.WhileStatement, SyntaxKind.DoStatement);
- }
-
- private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
- {
- var forLoop = context.Node as ForStatementSyntax;
- if (forLoop != null)
- {
- HandleFor(context, forLoop);
- return;
- }
-
- var whileLoop = context.Node as WhileStatementSyntax;
- if (whileLoop != null)
- {
- HandleWhile(context, whileLoop);
- return;
- }
-
- var foreachLoop = context.Node as ForEachStatementSyntax;
- if (foreachLoop != null)
- {
- HandleForeach(context, foreachLoop);
- return;
- }
-
- var doLoop = context.Node as DoStatementSyntax;
- if (doLoop != null)
- {
- HandleDo(context, doLoop);
- }
- }
-
- private void HandleFor(SyntaxNodeAnalysisContext context, ForStatementSyntax loop)
- {
- if (loop.Statement is BlockSyntax)
- {
- return;
- }
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, loop.ForKeyword.GetLocation()));
- }
-
- private void HandleWhile(SyntaxNodeAnalysisContext context, WhileStatementSyntax loop)
- {
- if (loop.Statement is BlockSyntax)
- {
- return;
- }
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, loop.WhileKeyword.GetLocation()));
- }
-
- private void HandleForeach(SyntaxNodeAnalysisContext context, ForEachStatementSyntax loop)
- {
- if (loop.Statement is BlockSyntax)
- {
- return;
- }
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, loop.ForEachKeyword.GetLocation()));
- }
-
- private void HandleDo(SyntaxNodeAnalysisContext context, DoStatementSyntax loop)
- {
- if (loop.Statement is BlockSyntax)
- {
- return;
- }
-
- context.ReportDiagnostic(Diagnostic.Create(Rule, loop.DoKeyword.GetLocation()));
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/LoopStatementWithoutBraces/LoopStatementWithoutBracesCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/LoopStatementWithoutBraces/LoopStatementWithoutBracesCodeFix.cs
deleted file mode 100644
index 977134d..0000000
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/LoopStatementWithoutBraces/LoopStatementWithoutBracesCodeFix.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using System.Collections.Immutable;
-using System.Composition;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CodeActions;
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-
-namespace VSDiagnostics.Diagnostics.General.LoopStatementWithoutBraces
-{
- [ExportCodeFixProvider("LoopWithoutBraces", LanguageNames.CSharp), Shared]
- public class LoopStatementWithoutBracesCodeFix : CodeFixProvider
- {
- public override ImmutableArray FixableDiagnosticIds
- => ImmutableArray.Create(LoopStatementWithoutBracesAnalyzer.Rule.Id);
-
- public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
-
- public override async Task RegisterCodeFixesAsync(CodeFixContext context)
- {
- var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
- var diagnostic = context.Diagnostics.First();
- var diagnosticSpan = diagnostic.Location.SourceSpan;
-
- var statement = root.FindNode(diagnosticSpan);
- context.RegisterCodeFix(
- CodeAction.Create(VSDiagnosticsResources.LoopStatementWithoutBracesCodeFixTitle,
- x => UseBracesNotationAsync(context.Document, root, statement),
- LoopStatementWithoutBracesAnalyzer.Rule.Id), diagnostic);
- }
-
- private Task UseBracesNotationAsync(Document document, SyntaxNode root, SyntaxNode statement)
- {
- SyntaxNode newBlock = null;
-
- var forSyntax = statement as ForStatementSyntax;
- if (forSyntax != null)
- {
- newBlock = GetNewBlock(statement, forSyntax.Statement);
- }
-
- var whileSyntax = statement as WhileStatementSyntax;
- if (whileSyntax != null)
- {
- newBlock = GetNewBlock(statement, whileSyntax.Statement);
- }
-
- var foreachSyntax = statement as ForEachStatementSyntax;
- if (foreachSyntax != null)
- {
- newBlock = GetNewBlock(statement, foreachSyntax.Statement);
- }
-
- var doSyntax = statement as DoStatementSyntax;
- if (doSyntax != null)
- {
- newBlock = GetNewBlock(statement, doSyntax.Statement);
- }
-
- var newRoot = root.ReplaceNode(statement, newBlock);
- var newDocument = document.WithSyntaxRoot(newRoot);
- return Task.FromResult(newDocument.Project.Solution);
- }
-
- private SyntaxNode GetNewBlock(SyntaxNode statement, StatementSyntax statementBody)
- {
- var body = SyntaxFactory.Block(statementBody);
- return statement.ReplaceNode(statementBody, body);
- }
- }
-}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/LoopedRandomInstantiation/LoopedRandomInstantiationAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/LoopedRandomInstantiation/LoopedRandomInstantiationAnalyzer.cs
new file mode 100644
index 0000000..2ffdec6
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/LoopedRandomInstantiation/LoopedRandomInstantiationAnalyzer.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.General.LoopedRandomInstantiation
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class LoopedRandomInstantiationAnalyzer : DiagnosticAnalyzer
+ {
+ private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
+ private static readonly string Category = VSDiagnosticsResources.GeneralCategory;
+ private static readonly string Message = VSDiagnosticsResources.LoopedRandomInstantiationAnalyzerMessage;
+ private static readonly string Title = VSDiagnosticsResources.LoopedRandomInstantiationAnalyzerTitle;
+
+ private readonly SyntaxKind[] _loopTypes = { SyntaxKind.ForEachStatement, SyntaxKind.ForStatement, SyntaxKind.WhileStatement, SyntaxKind.DoStatement };
+
+ internal static DiagnosticDescriptor Rule =>
+ new DiagnosticDescriptor(DiagnosticId.LoopedRandomInstantiation, Title, Message, Category, Severity, true);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.VariableDeclaration);
+
+ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
+ {
+ var variableDeclaration = (VariableDeclarationSyntax) context.Node;
+
+ var type = variableDeclaration.Type;
+ if (type == null)
+ {
+ return;
+ }
+
+ var typeInfo = context.SemanticModel.GetTypeInfo(type).Type;
+
+ if (typeInfo?.OriginalDefinition.ContainingNamespace == null ||
+ typeInfo.OriginalDefinition.ContainingNamespace.Name != nameof(System) ||
+ typeInfo.Name != nameof(Random))
+ {
+ return;
+ }
+
+ SyntaxNode currentNode = variableDeclaration;
+ while (!currentNode.IsAnyKind(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration))
+ {
+ if (_loopTypes.Contains(currentNode.Kind()))
+ {
+ foreach (var declarator in variableDeclaration.Variables)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule, declarator.GetLocation(), declarator.Identifier.Text));
+ }
+ return;
+ }
+
+ currentNode = currentNode.Parent;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/MissingBraces/MissingBracesAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/MissingBraces/MissingBracesAnalyzer.cs
new file mode 100644
index 0000000..8177165
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/MissingBraces/MissingBracesAnalyzer.cs
@@ -0,0 +1,142 @@
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.General.MissingBraces
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class MissingBracesAnalyzer : DiagnosticAnalyzer
+ {
+ private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
+
+ private static readonly string Category = VSDiagnosticsResources.GeneralCategory;
+ private static readonly string Message = VSDiagnosticsResources.MissingBracesAnalyzerMessage;
+ private static readonly string Title = VSDiagnosticsResources.MissingBracesAnalyzerTitle;
+
+ internal static DiagnosticDescriptor Rule
+ => new DiagnosticDescriptor(DiagnosticId.MissingBraces, Title, Message, Category, Severity, true);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.RegisterSyntaxNodeAction(AnalyzeIfSymbol, SyntaxKind.IfStatement);
+ context.RegisterSyntaxNodeAction(AnalyzeElseSymbol, SyntaxKind.ElseClause);
+ context.RegisterSyntaxNodeAction(AnalyzeForSymbol, SyntaxKind.ForStatement);
+ context.RegisterSyntaxNodeAction(AnalyzeForEachSymbol, SyntaxKind.ForEachStatement);
+ context.RegisterSyntaxNodeAction(AnalyzeWhileSymbol, SyntaxKind.WhileStatement);
+ context.RegisterSyntaxNodeAction(AnalyzeDoSymbol, SyntaxKind.DoStatement);
+ context.RegisterSyntaxNodeAction(AnalyzeUsingSymbol, SyntaxKind.UsingStatement);
+ context.RegisterSyntaxNodeAction(AnalyzeLockSymbol, SyntaxKind.LockStatement);
+ context.RegisterSyntaxNodeAction(AnalyzeFixedSymbol, SyntaxKind.FixedStatement);
+ context.RegisterSyntaxNodeAction(AnalyzeSwitchSection, SyntaxKind.SwitchSection);
+ }
+
+ private void AnalyzeIfSymbol(SyntaxNodeAnalysisContext context)
+ {
+ var ifStatement = (IfStatementSyntax)context.Node;
+ if (!ifStatement.Statement.IsKind(SyntaxKind.Block))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule,
+ ifStatement.IfKeyword.GetLocation(), "An", SyntaxFacts.GetText(SyntaxKind.IfKeyword)));
+ }
+ }
+
+ private void AnalyzeElseSymbol(SyntaxNodeAnalysisContext context)
+ {
+ var elseClause = (ElseClauseSyntax)context.Node;
+ if (!elseClause.Statement.IsKind(SyntaxKind.Block) &&
+ !elseClause.Statement.IsKind(SyntaxKind.IfStatement))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule,
+ elseClause.ElseKeyword.GetLocation(), "An", SyntaxFacts.GetText(SyntaxKind.ElseKeyword)));
+ }
+ }
+
+ private void AnalyzeForSymbol(SyntaxNodeAnalysisContext context)
+ {
+ var forStatement = (ForStatementSyntax)context.Node;
+ if (!forStatement.Statement.IsKind(SyntaxKind.Block))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule,
+ forStatement.ForKeyword.GetLocation(), "A", SyntaxFacts.GetText(SyntaxKind.ForKeyword)));
+ }
+ }
+
+ private void AnalyzeForEachSymbol(SyntaxNodeAnalysisContext context)
+ {
+ var forEachStatement = (ForEachStatementSyntax)context.Node;
+ if (!forEachStatement.Statement.IsKind(SyntaxKind.Block))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule,
+ forEachStatement.ForEachKeyword.GetLocation(), "A", SyntaxFacts.GetText(SyntaxKind.ForEachKeyword)));
+ }
+ }
+
+ private void AnalyzeWhileSymbol(SyntaxNodeAnalysisContext context)
+ {
+ var whileStatement = (WhileStatementSyntax)context.Node;
+ if (!whileStatement.Statement.IsKind(SyntaxKind.Block))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule,
+ whileStatement.WhileKeyword.GetLocation(), "A", SyntaxFacts.GetText(SyntaxKind.WhileKeyword)));
+ }
+ }
+
+ private void AnalyzeDoSymbol(SyntaxNodeAnalysisContext context)
+ {
+ var doStatement = (DoStatementSyntax)context.Node;
+ if (!doStatement.Statement.IsKind(SyntaxKind.Block))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule,
+ doStatement.DoKeyword.GetLocation(), "A", SyntaxFacts.GetText(SyntaxKind.DoKeyword)));
+ }
+ }
+
+ private void AnalyzeUsingSymbol(SyntaxNodeAnalysisContext context)
+ {
+ var usingStatement = (UsingStatementSyntax)context.Node;
+ if (!usingStatement.Statement.IsKind(SyntaxKind.Block) &&
+ !usingStatement.Statement.IsKind(SyntaxKind.UsingStatement))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule,
+ usingStatement.UsingKeyword.GetLocation(), "A", SyntaxFacts.GetText(SyntaxKind.UsingKeyword)));
+ }
+ }
+
+ private void AnalyzeLockSymbol(SyntaxNodeAnalysisContext context)
+ {
+ var lockStatement = (LockStatementSyntax)context.Node;
+ if (!lockStatement.Statement.IsKind(SyntaxKind.Block) &&
+ !lockStatement.Statement.IsKind(SyntaxKind.LockStatement))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule,
+ lockStatement.LockKeyword.GetLocation(), "A", SyntaxFacts.GetText(SyntaxKind.LockKeyword)));
+ }
+ }
+
+ private void AnalyzeFixedSymbol(SyntaxNodeAnalysisContext context)
+ {
+ var fixedStatement = (FixedStatementSyntax)context.Node;
+ if (!fixedStatement.Statement.IsKind(SyntaxKind.Block) &&
+ !fixedStatement.Statement.IsKind(SyntaxKind.FixedStatement))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule,
+ fixedStatement.FixedKeyword.GetLocation(), "A", SyntaxFacts.GetText(SyntaxKind.FixedKeyword)));
+ }
+ }
+
+ private void AnalyzeSwitchSection(SyntaxNodeAnalysisContext context)
+ {
+ var switchSection = (SwitchSectionSyntax)context.Node;
+ if (switchSection.Statements.Count != 1 || !switchSection.Statements[0].IsKind(SyntaxKind.Block))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule,
+ switchSection.GetLocation(), "A", "switch section"));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/MissingBraces/MissingBracesCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/MissingBraces/MissingBracesCodeFix.cs
new file mode 100644
index 0000000..b67d409
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/MissingBraces/MissingBracesCodeFix.cs
@@ -0,0 +1,102 @@
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Formatting;
+using VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.General.MissingBraces
+{
+ [ExportCodeFixProvider(DiagnosticId.MissingBraces + "CF", LanguageNames.CSharp), Shared]
+ public class MissingBracesCodeFix : CodeFixProvider
+ {
+ public override ImmutableArray FixableDiagnosticIds
+ => ImmutableArray.Create(MissingBracesAnalyzer.Rule.Id);
+
+ public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
+
+ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var diagnostic = context.Diagnostics.First();
+
+ context.RegisterCodeFix(
+ CodeAction.Create(VSDiagnosticsResources.MissingBracesCodeFixTitle,
+ x => AddBracesAsync(context, x),
+ MissingBracesAnalyzer.Rule.Id), diagnostic);
+ }
+
+ private async Task AddBracesAsync(CodeFixContext context, CancellationToken cancellationToken)
+ {
+ var root = await context.Document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
+ var diagnostic = context.Diagnostics.First();
+ var diagnosticSpan = diagnostic.Location.SourceSpan;
+ var statement = root.FindNode(diagnosticSpan);
+
+ var newRoot = root.ReplaceNode(statement, GetReplacementNode(statement));
+ return context.Document.WithSyntaxRoot(newRoot);
+ }
+
+ private SyntaxNode GetReplacementNode(SyntaxNode statement)
+ {
+ switch (statement.Kind())
+ {
+ case SyntaxKind.IfStatement:
+ var ifSyntax = (IfStatementSyntax)statement;
+ return GetNewBlock(statement, ifSyntax.Statement);
+
+ case SyntaxKind.ElseClause:
+ var elseClause = (ElseClauseSyntax)statement;
+ return GetNewBlock(statement, elseClause.Statement);
+
+ case SyntaxKind.ForStatement:
+ var forSyntax = (ForStatementSyntax)statement;
+ return GetNewBlock(statement, forSyntax.Statement);
+
+ case SyntaxKind.ForEachStatement:
+ var forEachSyntax = (ForEachStatementSyntax)statement;
+ return GetNewBlock(statement, forEachSyntax.Statement);
+
+ case SyntaxKind.WhileStatement:
+ var whileSyntax = (WhileStatementSyntax)statement;
+ return GetNewBlock(statement, whileSyntax.Statement);
+
+ case SyntaxKind.DoStatement:
+ var doSyntax = (DoStatementSyntax)statement;
+ return GetNewBlock(statement, doSyntax.Statement);
+
+ case SyntaxKind.UsingStatement:
+ var usingSyntax = (UsingStatementSyntax)statement;
+ return GetNewBlock(statement, usingSyntax.Statement);
+
+ case SyntaxKind.LockStatement:
+ var lockSyntax = (LockStatementSyntax)statement;
+ return GetNewBlock(statement, lockSyntax.Statement);
+
+ case SyntaxKind.FixedStatement:
+ var fixedSyntax = (FixedStatementSyntax)statement;
+ return GetNewBlock(statement, fixedSyntax.Statement);
+
+ case SyntaxKind.SwitchSection:
+ var switchSectionSyntax = (SwitchSectionSyntax)statement;
+ return GetNewBlock(statement, switchSectionSyntax);
+ }
+
+ return default(SyntaxNode);
+ }
+
+ private SyntaxNode GetNewBlock(SyntaxNode statement, StatementSyntax statementBody) =>
+ statement.ReplaceNode(statementBody, SyntaxFactory.Block(statementBody).WithAdditionalAnnotations(Formatter.Annotation));
+
+ private SyntaxNode GetNewBlock(SyntaxNode statement, SwitchSectionSyntax switchSection) =>
+ statement.ReplaceNode(switchSection,
+ SyntaxFactory.SwitchSection(switchSection.Labels,
+ SyntaxFactory.List(new[]
+ {SyntaxFactory.Block(switchSection.Statements).WithAdditionalAnnotations(Formatter.Annotation)})));
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsAnalyzer.cs
index 18cae52..771c3f7 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsAnalyzer.cs
@@ -23,26 +23,23 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics
=> ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol,
- SyntaxKind.FieldDeclaration,
- SyntaxKind.PropertyDeclaration,
- SyntaxKind.MethodDeclaration,
- SyntaxKind.ClassDeclaration,
- SyntaxKind.InterfaceDeclaration,
- SyntaxKind.LocalDeclarationStatement,
- SyntaxKind.Parameter,
- SyntaxKind.StructDeclaration,
- SyntaxKind.EnumDeclaration,
- SyntaxKind.EnumMemberDeclaration);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol,
+ SyntaxKind.FieldDeclaration,
+ SyntaxKind.PropertyDeclaration,
+ SyntaxKind.MethodDeclaration,
+ SyntaxKind.ClassDeclaration,
+ SyntaxKind.InterfaceDeclaration,
+ SyntaxKind.LocalDeclarationStatement,
+ SyntaxKind.Parameter,
+ SyntaxKind.StructDeclaration,
+ SyntaxKind.EnumDeclaration,
+ SyntaxKind.EnumMemberDeclaration);
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
- var nodeAsField = context.Node as FieldDeclarationSyntax;
- if (nodeAsField != null)
+ if (context.Node.IsKind(SyntaxKind.FieldDeclaration))
{
+ var nodeAsField = (FieldDeclarationSyntax) context.Node;
if (nodeAsField.Declaration == null)
{
return;
@@ -79,38 +76,38 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
return;
}
- var nodeAsProperty = context.Node as PropertyDeclarationSyntax;
- if (nodeAsProperty != null)
+ if (context.Node.IsKind(SyntaxKind.PropertyDeclaration))
{
+ var nodeAsProperty = (PropertyDeclarationSyntax) context.Node;
CheckNaming(nodeAsProperty.Identifier, "property", NamingConvention.UpperCamelCase, context);
return;
}
- var nodeAsMethod = context.Node as MethodDeclarationSyntax;
- if (nodeAsMethod != null)
+ if (context.Node.IsKind(SyntaxKind.MethodDeclaration))
{
+ var nodeAsMethod = (MethodDeclarationSyntax) context.Node;
CheckNaming(nodeAsMethod.Identifier, "method", NamingConvention.UpperCamelCase, context);
return;
}
- var nodeAsClass = context.Node as ClassDeclarationSyntax;
- if (nodeAsClass != null)
+ if (context.Node.IsKind(SyntaxKind.ClassDeclaration))
{
+ var nodeAsClass = (ClassDeclarationSyntax) context.Node;
CheckNaming(nodeAsClass.Identifier, "class", NamingConvention.UpperCamelCase, context);
return;
}
- var nodeAsInterface = context.Node as InterfaceDeclarationSyntax;
- if (nodeAsInterface != null)
+ if (context.Node.IsKind(SyntaxKind.InterfaceDeclaration))
{
+ var nodeAsInterface = (InterfaceDeclarationSyntax) context.Node;
CheckNaming(nodeAsInterface.Identifier, "interface", NamingConvention.InterfacePrefixUpperCamelCase,
context);
return;
}
- var nodeAsLocal = context.Node as LocalDeclarationStatementSyntax;
- if (nodeAsLocal != null)
+ if (context.Node.IsKind(SyntaxKind.LocalDeclarationStatement))
{
+ var nodeAsLocal = (LocalDeclarationStatementSyntax) context.Node;
if (nodeAsLocal.Declaration == null)
{
return;
@@ -124,45 +121,44 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
return;
}
- var nodeAsParameter = context.Node as ParameterSyntax;
- if (nodeAsParameter != null)
+ if (context.Node.IsKind(SyntaxKind.Parameter))
{
+ var nodeAsParameter = (ParameterSyntax) context.Node;
CheckNaming(nodeAsParameter.Identifier, "parameter", NamingConvention.LowerCamelCase, context);
return;
}
- var nodeAsStruct = context.Node as StructDeclarationSyntax;
- if (nodeAsStruct != null)
+ if (context.Node.IsKind(SyntaxKind.StructDeclaration))
{
+ var nodeAsStruct = (StructDeclarationSyntax) context.Node;
CheckNaming(nodeAsStruct.Identifier, "struct", NamingConvention.UpperCamelCase, context);
return;
}
- var nodeAsEnum = context.Node as EnumDeclarationSyntax;
- if (nodeAsEnum != null)
+ if (context.Node.IsKind(SyntaxKind.EnumDeclaration))
{
+ var nodeAsEnum = (EnumDeclarationSyntax) context.Node;
CheckNaming(nodeAsEnum.Identifier, "enum", NamingConvention.UpperCamelCase, context);
return;
}
- var nodeAsEnumMember = context.Node as EnumMemberDeclarationSyntax;
- if (nodeAsEnumMember != null)
+ if (context.Node.IsKind(SyntaxKind.EnumMemberDeclaration))
{
+ var nodeAsEnumMember = (EnumMemberDeclarationSyntax) context.Node;
CheckNaming(nodeAsEnumMember.Identifier, "enum member", NamingConvention.UpperCamelCase, context);
- return;
}
}
private static void CheckNaming(SyntaxToken currentIdentifier, string memberType, NamingConvention convention,
- SyntaxNodeAnalysisContext context)
+ SyntaxNodeAnalysisContext context)
{
var conventionedIdentifier = currentIdentifier.WithConvention(convention);
if (conventionedIdentifier.Text != currentIdentifier.Text)
{
context.ReportDiagnostic(
- Diagnostic.Create(Rule, currentIdentifier.GetLocation(),
- ImmutableDictionary.CreateRange( new[] { new KeyValuePair("convention", convention.ToString()) }),
- memberType, currentIdentifier.Text, conventionedIdentifier.Text));
+ Diagnostic.Create(Rule, currentIdentifier.GetLocation(),
+ ImmutableDictionary.CreateRange(new[] { new KeyValuePair("convention", convention.ToString()) }),
+ memberType, currentIdentifier.Text, conventionedIdentifier.Text));
}
}
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsCodeFix.cs
index ed469b3..363634c 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsCodeFix.cs
@@ -7,13 +7,11 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.General.NamingConventions
{
- [ExportCodeFixProvider(nameof(NamingConventionsCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.NamingConventions + "CF", LanguageNames.CSharp), Shared]
public class NamingConventionsCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds
@@ -30,7 +28,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
var identifier = root.FindToken(diagnosticSpan.Start);
context.RegisterCodeFix(
CodeAction.Create(VSDiagnosticsResources.NamingConventionsCodeFixTitle,
- x => RenameAsync(context.Document, identifier, root, diagnostic, context.CancellationToken), NamingConventionsAnalyzer.Rule.Id), diagnostic);
+ x => RenameAsync(context.Document, identifier, root, diagnostic, x), NamingConventionsAnalyzer.Rule.Id), diagnostic);
}
private async Task RenameAsync(Document document, SyntaxToken identifier, SyntaxNode root, Diagnostic diagnostic, CancellationToken cancellationToken)
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NonEncapsulatedOrMutableField/NonEncapsulatedOrMutableFieldAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NonEncapsulatedOrMutableField/NonEncapsulatedOrMutableFieldAnalyzer.cs
index 83a7b4a..609f7b6 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NonEncapsulatedOrMutableField/NonEncapsulatedOrMutableFieldAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NonEncapsulatedOrMutableField/NonEncapsulatedOrMutableFieldAnalyzer.cs
@@ -1,11 +1,9 @@
-using System.Collections.Generic;
-using System.Collections.Immutable;
+using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.CodeAnalysis.FindSymbols;
using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.General.NonEncapsulatedOrMutableField
@@ -24,29 +22,20 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.FieldDeclaration);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.FieldDeclaration);
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
- var fieldDeclaration = context.Node as FieldDeclarationSyntax;
- if (fieldDeclaration == null)
- {
- return;
- }
+ var fieldDeclaration = (FieldDeclarationSyntax) context.Node;
// Don't handle (semi-)immutable fields
- if (fieldDeclaration.Modifiers.Any(
- x => x.IsKind(SyntaxKind.ConstKeyword) || x.IsKind(SyntaxKind.ReadOnlyKeyword)))
+ if (fieldDeclaration.Modifiers.ContainsAny(SyntaxKind.ConstKeyword, SyntaxKind.ReadOnlyKeyword))
{
return;
}
// Only handle public, internal and protected internal fields
- if (!fieldDeclaration.Modifiers.Any(
- x => x.IsKind(SyntaxKind.PublicKeyword) || x.IsKind(SyntaxKind.InternalKeyword)))
+ if (!fieldDeclaration.Modifiers.ContainsAny(SyntaxKind.PublicKeyword, SyntaxKind.InternalKeyword))
{
return;
}
@@ -80,7 +69,7 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
// In this scenario our analyzer is triggered on the field in class X and won't find any references inside that syntax tree (assuming separate files)
// However it won't find any ref/out usages there so it will create the diagnostic -- which obviously isn't supposed to happen because the other syntax tree DOES contain that
// However until this ability is added, we'll just have to live with it
- var outerClass = context.Node.Ancestors().OfType().LastOrDefault();
+ var outerClass = context.Node.Ancestors().OfType(SyntaxKind.ClassDeclaration).LastOrDefault();
if (outerClass != null)
{
var semanticModel = context.SemanticModel;
@@ -89,15 +78,15 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
var fieldSymbol = semanticModel.GetDeclaredSymbol(variable);
- foreach (var descendant in outerClass.DescendantNodes().OfType())
+ foreach (var descendant in outerClass.DescendantNodes().OfType(SyntaxKind.IdentifierName))
{
var descendentSymbol = semanticModel.GetSymbolInfo(descendant).Symbol;
if (descendentSymbol != null && descendentSymbol.Equals(fieldSymbol))
{
// The field is being referenced
// Next we check whether it is referenced as an argument and passed by ref/out
- var argument = descendant.AncestorsAndSelf().OfType().FirstOrDefault();
- if (argument != null && !argument.RefOrOutKeyword.IsMissing)
+ var argument = descendant.AncestorsAndSelf().OfType(SyntaxKind.Argument).FirstOrDefault();
+ if (argument != null && !argument.RefOrOutKeyword.IsKind(SyntaxKind.None))
{
return;
}
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NonEncapsulatedOrMutableField/NonEncapsulatedOrMutableFieldCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NonEncapsulatedOrMutableField/NonEncapsulatedOrMutableFieldCodeFix.cs
index 96284ee..bcc3731 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NonEncapsulatedOrMutableField/NonEncapsulatedOrMutableFieldCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NonEncapsulatedOrMutableField/NonEncapsulatedOrMutableFieldCodeFix.cs
@@ -9,12 +9,11 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
-using VSDiagnostics.Diagnostics.General.NamingConventions;
using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.General.NonEncapsulatedOrMutableField
{
- [ExportCodeFixProvider(nameof(NonEncapsulatedOrMutableFieldCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.NonEncapsulatedOrMutableField + "CF", LanguageNames.CSharp), Shared]
public class NonEncapsulatedOrMutableFieldCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds
@@ -47,24 +46,24 @@ private async Task UsePropertyAsync(Document document, SyntaxNode stat
var variableDeclaration = variableDeclarator.AncestorsAndSelf().OfType().First();
var newProperty = SyntaxFactory.PropertyDeclaration(variableDeclaration.Type, variableDeclarator.Identifier)
- .WithAttributeLists(fieldStatement.AttributeLists)
- .WithModifiers(fieldStatement.Modifiers)
- .WithAdditionalAnnotations(Formatter.Annotation)
- .WithAccessorList(
- SyntaxFactory.AccessorList(
- SyntaxFactory.List(new[]
- {
- SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
- .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
- SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
- .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
- })));
+ .WithAttributeLists(fieldStatement.AttributeLists)
+ .WithModifiers(fieldStatement.Modifiers)
+ .WithAdditionalAnnotations(Formatter.Annotation)
+ .WithAccessorList(
+ SyntaxFactory.AccessorList(
+ SyntaxFactory.List(new[]
+ {
+ SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
+ .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
+ SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
+ .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
+ })));
if (variableDeclarator.Initializer != null)
{
newProperty =
newProperty.WithInitializer(variableDeclarator.Initializer)
- .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
+ .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
}
var editor = await DocumentEditor.CreateAsync(document);
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NullableToShorthand/NullableToShorthandAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NullableToShorthand/NullableToShorthandAnalyzer.cs
index 4784158..35bace3 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NullableToShorthand/NullableToShorthandAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NullableToShorthand/NullableToShorthandAnalyzer.cs
@@ -22,15 +22,12 @@ internal static DiagnosticDescriptor Rule
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.GenericName);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.GenericName);
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
var argumentList = (GenericNameSyntax) context.Node;
- if (argumentList.TypeArgumentList.Arguments.OfType().Any())
+ if (argumentList.TypeArgumentList.Arguments.OfType(SyntaxKind.OmittedTypeArgument).Any())
{
return;
}
@@ -67,31 +64,40 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
// First we look through the different nodes that can't be nested
// If nothing is found, we check if it's perhaps a standalone expression (such as an object creation without assigning it to an identifier)
- var parentNode =
- context.Node.AncestorsAndSelf().FirstOrDefault(x => variableAncestorNodes.Contains(x.Kind())) ??
- context.Node.AncestorsAndSelf().OfType().FirstOrDefault();
+ SyntaxNode parentNode = null;
+ foreach (var node in context.Node.AncestorsAndSelf())
+ {
+ if (variableAncestorNodes.Contains(node.Kind()))
+ {
+ parentNode = node;
+ }
+ }
if (parentNode == null)
{
- return;
+ parentNode = context.Node.AncestorsAndSelf().OfType(SyntaxKind.ExpressionStatement).FirstOrDefault();
+
+ if (parentNode == null)
+ {
+ return;
+ }
}
if (parentNode.Kind() == SyntaxKind.LocalDeclarationStatement)
{
identifier = ((LocalDeclarationStatementSyntax) parentNode).Declaration?
- .Variables
- .FirstOrDefault()?
- .Identifier
- .Text;
+ .Variables
+ .FirstOrDefault()?
+ .Identifier
+ .Text;
}
else if (parentNode.Kind() == SyntaxKind.FieldDeclaration)
{
- identifier =
- ((FieldDeclarationSyntax) parentNode).Declaration?
- .Variables
- .FirstOrDefault()?
- .Identifier
- .Text;
+ identifier = ((FieldDeclarationSyntax) parentNode).Declaration?
+ .Variables
+ .FirstOrDefault()?
+ .Identifier
+ .Text;
}
else if (parentNode.Kind() == SyntaxKind.Parameter)
{
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NullableToShorthand/NullableToShorthandCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NullableToShorthand/NullableToShorthandCodeFix.cs
index 0dcfce4..79dde7f 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NullableToShorthand/NullableToShorthandCodeFix.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NullableToShorthand/NullableToShorthandCodeFix.cs
@@ -8,10 +8,11 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
+using VSDiagnostics.Utilities;
namespace VSDiagnostics.Diagnostics.General.NullableToShorthand
{
- [ExportCodeFixProvider(nameof(NullableToShorthandCodeFix), LanguageNames.CSharp), Shared]
+ [ExportCodeFixProvider(DiagnosticId.NullableToShorthand + "CF", LanguageNames.CSharp), Shared]
public class NullableToShorthandCodeFix : CodeFixProvider
{
public override ImmutableArray FixableDiagnosticIds
@@ -32,8 +33,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
NullableToShorthandAnalyzer.Rule.Id), diagnostic);
}
- private static async Task UseShorthandNotationAsync(Document document, SyntaxNode root,
- SyntaxToken declaration)
+ private static async Task UseShorthandNotationAsync(Document document, SyntaxNode root, SyntaxToken declaration)
{
var node = root.FindNode(declaration.Span);
var typeNode = (GenericNameSyntax) node;
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/OnPropertyChangedWithoutNameOfOperator/OnPropertyChangedWithoutNameOfOperatorAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/OnPropertyChangedWithoutNameOfOperator/OnPropertyChangedWithoutNameOfOperatorAnalyzer.cs
index bc1cc09..21f4c97 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/OnPropertyChangedWithoutNameOfOperator/OnPropertyChangedWithoutNameOfOperatorAnalyzer.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/OnPropertyChangedWithoutNameOfOperator/OnPropertyChangedWithoutNameOfOperatorAnalyzer.cs
@@ -15,32 +15,21 @@ namespace VSDiagnostics.Diagnostics.General.OnPropertyChangedWithoutNameOfOperat
public class OnPropertyChangedWithoutNameOfOperatorAnalyzer : DiagnosticAnalyzer
{
private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
-
private static readonly string Category = VSDiagnosticsResources.GeneralCategory;
+ private static readonly string Message = VSDiagnosticsResources.OnPropertyChangedWithoutNameOfOperatorAnalyzerMessage;
+ private static readonly string Title = VSDiagnosticsResources.OnPropertyChangedWithoutNameOfOperatorAnalyzerTitle;
- private static readonly string Message =
- VSDiagnosticsResources.OnPropertyChangedWithoutNameOfOperatorAnalyzerMessage;
-
- private static readonly string Title =
- VSDiagnosticsResources.OnPropertyChangedWithoutNameOfOperatorAnalyzerTitle;
-
- internal static DiagnosticDescriptor Rule
- =>
- new DiagnosticDescriptor(DiagnosticId.OnPropertyChangedWithoutNameofOperator, Title, Message, Category,
- Severity, true);
+ internal static DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId.OnPropertyChangedWithoutNameofOperator, Title, Message, Category, Severity, true);
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
- public override void Initialize(AnalysisContext context)
- {
- context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.InvocationExpression);
- }
+ public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.InvocationExpression);
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
- var invocation = context.Node as InvocationExpressionSyntax;
+ var invocation = (InvocationExpressionSyntax) context.Node;
- var identifierExpression = invocation?.Expression as IdentifierNameSyntax;
+ var identifierExpression = invocation.Expression as IdentifierNameSyntax;
if (identifierExpression == null)
{
return;
@@ -64,9 +53,12 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
}
// We use the descendent nodes in case it's wrapped in another level. For example: OnPropertyChanged(((nameof(MyProperty))))
- if (invokedProperty.DescendantNodesAndSelf().OfType