diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/NamingConventionsAnalyzerTests.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/NamingConventionsAnalyzerTests.cs
new file mode 100644
index 0000000..6ca1b73
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/Tests/General/NamingConventionsAnalyzerTests.cs
@@ -0,0 +1,1143 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RoslynTester.DiagnosticResults;
+using RoslynTester.Helpers.CSharp;
+using VSDiagnostics.Diagnostics.General.NamingConventions;
+
+namespace VSDiagnostics.Test.Tests.General
+{
+ [TestClass]
+ public class NamingConventionsAnalyzerTests : CSharpCodeFixVerifier
+ {
+ protected override DiagnosticAnalyzer DiagnosticAnalyzer => new NamingConventionsAnalyzer();
+ protected override CodeFixProvider CodeFixProvider => new NamingConventionsCodeFix();
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithPrivateField_AndCapitalStart_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ private int X;
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ private int _x;
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "field", "X", "_x"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 21)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithPrivateField_AndCapitalStartWithUnderscore_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ private int _X;
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ private int _x;
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "field", "_X", "_x"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 21)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithPublicField_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int x;
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int X;
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "field", "x", "X"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 20)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithProtectedField_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ protected int x;
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ protected int X;
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "field", "x", "X"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 23)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithInternalField_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ internal int x;
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ internal int X;
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "field", "x", "X"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 22)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithProtectedInternalField_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ protected internal int x;
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ protected internal int X;
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "field", "x", "X"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 32)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithProperty_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int x { get; set; }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int X { get; set; }
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "property", "x", "X"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 20)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithMethod_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void method()
+ {
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ }
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "method", "method", "Method"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 14)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithClass_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class myClass
+ {
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "class", "myClass", "MyClass"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 7, 11)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithInterface_WithoutPrefix_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ interface something
+ {
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ interface ISomething
+ {
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "interface", "something", "ISomething"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 7, 15)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithInterface_WithPrefix_AndLowerSecondLetter_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ interface Isomething
+ {
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ interface ISomething
+ {
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "interface", "Isomething", "ISomething"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 7, 15)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithInterface_WithlowerPrefix_AndCapitalSecondLetter_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ interface iSomething
+ {
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ interface ISomething
+ {
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "interface", "iSomething", "ISomething"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 7, 15)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithLocalVariable_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var MyVar = 5;
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ var myVar = 5;
+ }
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "local", "MyVar", "myVar"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 11, 17)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithParameter_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(string Param)
+ {
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(string param)
+ {
+ }
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "parameter", "Param", "param"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 28)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithMultipleFields_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ private int X, Y;
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ private int _x, _y;
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "field", "X", "_x"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 21)
+ }
+ };
+
+ var expectedDiagnostic2 = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "field", "Y", "_y"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 24)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic, expectedDiagnostic2);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithPrivateField_FollowingConventions_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ private int _x;
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithProtectedField_FollowingConventions_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ protected int X;
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithInternalField_FollowingConventions_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ internal int X;
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithPublicField_FollowingConventions_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int X;
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithInternalProtectedField_FollowingConventions_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ internal protected int X;
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithProperty_FollowingConventions_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ private int X { get; set; }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithMethod_FollowingConventions_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithClass_FollowingConventions_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithInterface_FollowingConventions_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ interface ISomething
+ {
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithLocalVariable_FollowingConventions_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ string myVar = string.Empty;
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithParameter_FollowingConventions_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method(string param)
+ {
+ }
+ }
+}";
+
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithVerbatimIdentifier_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int @class;
+ }
+}";
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithEscapedIdentifier_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ public int \u0061ss;
+ }
+}";
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithMultipleDifferentTypes_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ internal int x;
+
+ void method()
+ {
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ internal int X;
+
+ void Method()
+ {
+ }
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "field", "x", "X"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 22)
+ }
+ };
+
+ var expectedDiagnostic2 = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "method", "method", "Method"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 11, 14)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic, expectedDiagnostic2);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithMultipleSimilarTypes_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ int X, Y;
+ }
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ void Method()
+ {
+ int x, y;
+ }
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "local", "X", "x"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 11, 17)
+ }
+ };
+
+ var expectedDiagnostic2 = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "local", "Y", "y"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 11, 20)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic, expectedDiagnostic2);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithExclusivelySpecialCharacters_DoesNotInvokeWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ protected int ___;
+ }
+}";
+ VerifyDiagnostic(original);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithOneLetterPrivateVariable_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ private int x;
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ private int _x;
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "field", "x", "_x"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 21)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+
+ [TestMethod]
+ public void NamingConventionsAnalyzer_WithPrivateField_WithoutAccessModifier_InvokesWarning()
+ {
+ var original = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ int X;
+ }
+}";
+
+ var result = @"
+using System;
+using System.Text;
+
+namespace ConsoleApplication1
+{
+ class MyClass
+ {
+ int _x;
+ }
+}";
+
+ var expectedDiagnostic = new DiagnosticResult
+ {
+ Id = NamingConventionsAnalyzer.DiagnosticId,
+ Message = string.Format(NamingConventionsAnalyzer.Message, "field", "X", "_x"),
+ Severity = NamingConventionsAnalyzer.Severity,
+ Locations =
+ new[]
+ {
+ new DiagnosticResultLocation("Test0.cs", 9, 13)
+ }
+ };
+
+ VerifyDiagnostic(original, expectedDiagnostic);
+ VerifyFix(original, result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/VSDiagnostics.Test.csproj b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/VSDiagnostics.Test.csproj
index b275b95..c3f8b2e 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/VSDiagnostics.Test.csproj
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/VSDiagnostics.Test.csproj
@@ -121,6 +121,7 @@
+
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/packages.config b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/packages.config
index 1cb831c..bee7325 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/packages.config
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics.Test/packages.config
@@ -1,10 +1,16 @@
+
-
-
-
-
-
+
+
+
+
+
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsAnalyzer.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsAnalyzer.cs
new file mode 100644
index 0000000..d7ab9d1
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsAnalyzer.cs
@@ -0,0 +1,119 @@
+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.NamingConventions
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class NamingConventionsAnalyzer : DiagnosticAnalyzer
+ {
+ public const string DiagnosticId = nameof(NamingConventionsAnalyzer);
+ internal const string Title = "A member does not follow naming conventions.";
+ internal const string Message = "The {0} {1} does not follow naming conventions. Should be {2}.";
+ internal const string Category = "General";
+ internal const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
+ internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, Severity, true);
+ 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);
+ }
+
+ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
+ {
+ var nodeAsField = context.Node as FieldDeclarationSyntax;
+ if (nodeAsField != null)
+ {
+ if (nodeAsField.Declaration == null)
+ {
+ return;
+ }
+
+ foreach (var variable in nodeAsField.Declaration.Variables)
+ {
+ if (nodeAsField.Modifiers.Any(x => new[] { "internal", "protected", "public" }.Contains(x.Text)))
+ {
+ CheckNaming(variable.Identifier, "field", NamingConvention.UpperCamelCase, context);
+ }
+ else if (nodeAsField.Modifiers.Any(x => x.Text == "private") || nodeAsField.Modifiers.Count == 0 /* no access modifier defaults to private */)
+ {
+ CheckNaming(variable.Identifier, "field", NamingConvention.UnderscoreLowerCamelCase, context);
+ }
+ else
+ {
+ return; // Code is in an incomplete state
+ }
+ }
+
+ return;
+ }
+
+ var nodeAsProperty = context.Node as PropertyDeclarationSyntax;
+ if (nodeAsProperty != null)
+ {
+ CheckNaming(nodeAsProperty.Identifier, "property", NamingConvention.UpperCamelCase, context);
+ }
+
+ var nodeAsMethod = context.Node as MethodDeclarationSyntax;
+ if (nodeAsMethod != null)
+ {
+ CheckNaming(nodeAsMethod.Identifier, "method", NamingConvention.UpperCamelCase, context);
+ }
+
+ var nodeAsClass = context.Node as ClassDeclarationSyntax;
+ if (nodeAsClass != null)
+ {
+ CheckNaming(nodeAsClass.Identifier, "class", NamingConvention.UpperCamelCase, context);
+ }
+
+ var nodeAsInterface = context.Node as InterfaceDeclarationSyntax;
+ if (nodeAsInterface != null)
+ {
+ CheckNaming(nodeAsInterface.Identifier, "interface", NamingConvention.InterfacePrefixUpperCamelCase, context);
+ }
+
+ var nodeAsLocal = context.Node as LocalDeclarationStatementSyntax;
+ if (nodeAsLocal != null)
+ {
+ if (nodeAsLocal.Declaration == null)
+ {
+ return;
+ }
+
+ foreach (var variable in nodeAsLocal.Declaration.Variables)
+ {
+ CheckNaming(variable.Identifier, "local", NamingConvention.LowerCamelCase, context);
+ }
+
+ return;
+ }
+
+ var nodeAsParameter = context.Node as ParameterSyntax;
+ if (nodeAsParameter != null)
+ {
+ CheckNaming(nodeAsParameter.Identifier, "parameter", NamingConvention.LowerCamelCase, context);
+ }
+ }
+
+ private void CheckNaming(SyntaxToken currentIdentifier, string memberType, NamingConvention convention, SyntaxNodeAnalysisContext context)
+ {
+ var conventionedIdentifier = currentIdentifier.WithConvention(convention);
+ if (conventionedIdentifier.Text != currentIdentifier.Text)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(Rule, currentIdentifier.GetLocation(), memberType, currentIdentifier.Text, conventionedIdentifier.Text));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsCodeFix.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsCodeFix.cs
new file mode 100644
index 0000000..b3a842a
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Diagnostics/General/NamingConventions/NamingConventionsCodeFix.cs
@@ -0,0 +1,76 @@
+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 VSDiagnostics.Utilities;
+
+namespace VSDiagnostics.Diagnostics.General.NamingConventions
+{
+ [ExportCodeFixProvider("NamingConventions", LanguageNames.CSharp), Shared]
+ public class NamingConventionsCodeFix : CodeFixProvider
+ {
+ public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(NamingConventionsAnalyzer.DiagnosticId);
+ 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 identifier = root.FindToken(diagnosticSpan.Start);
+ context.RegisterCodeFix(CodeAction.Create("Rename", x => RenameAsync(context.Document, root, identifier)), diagnostic);
+ }
+
+ private Task RenameAsync(Document document, SyntaxNode root, SyntaxToken identifier)
+ {
+ var identifierParent = identifier.Parent;
+ var newIdentifier = default(SyntaxToken);
+
+ do
+ {
+ var parentAsField = identifierParent as FieldDeclarationSyntax;
+ if (parentAsField != null)
+ {
+ if (parentAsField.Modifiers.Any(x => new[] { "internal", "protected", "public" }.Contains(x.Text)))
+ {
+ newIdentifier = identifier.WithConvention(NamingConvention.UpperCamelCase);
+ }
+ else
+ {
+ newIdentifier = identifier.WithConvention(NamingConvention.UnderscoreLowerCamelCase);
+ }
+ break;
+ }
+
+ if (identifierParent is PropertyDeclarationSyntax || identifierParent is MethodDeclarationSyntax || identifierParent is ClassDeclarationSyntax)
+ {
+ newIdentifier = identifier.WithConvention(NamingConvention.UpperCamelCase);
+ break;
+ }
+
+ if (identifierParent is LocalDeclarationStatementSyntax || identifierParent is ParameterSyntax)
+ {
+ newIdentifier = identifier.WithConvention(NamingConvention.LowerCamelCase);
+ break;
+ }
+
+ if (identifierParent is InterfaceDeclarationSyntax)
+ {
+ newIdentifier = identifier.WithConvention(NamingConvention.InterfacePrefixUpperCamelCase);
+ break;
+ }
+
+ identifierParent = identifierParent.Parent;
+ } while (identifierParent != null);
+
+ var newParent = identifierParent.ReplaceToken(identifier, newIdentifier);
+ var newRoot = root.ReplaceNode(identifierParent, newParent);
+ return Task.FromResult(document.WithSyntaxRoot(newRoot).Project.Solution);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Utilities/Extensions.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Utilities/Extensions.cs
index 9b07016..c4d3ded 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Utilities/Extensions.cs
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Utilities/Extensions.cs
@@ -1,5 +1,7 @@
using System;
+using System.Linq;
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
namespace VSDiagnostics.Utilities
{
@@ -24,5 +26,152 @@ public static bool InheritsFrom(this ISymbol typeSymbol, Type type)
return false;
}
+
+ public static SyntaxToken WithConvention(this SyntaxToken identifier, NamingConvention namingConvention)
+ {
+ // int @class = 5;
+ if (identifier.IsVerbatimIdentifier())
+ {
+ return identifier;
+ }
+
+ // int cl\u0061ss = 5;
+ if (identifier.Text.Contains("\\"))
+ {
+ return identifier;
+ }
+
+ var originalValue = identifier.ValueText;
+ string newValue;
+
+ switch (namingConvention)
+ {
+ case NamingConvention.LowerCamelCase:
+ newValue = GetLowerCamelCaseIdentifier(originalValue);
+ break;
+ case NamingConvention.UpperCamelCase:
+ newValue = GetUpperCamelCaseIdentifier(originalValue);
+ break;
+ case NamingConvention.UnderscoreLowerCamelCase:
+ newValue = GetUnderscoreLowerCamelCaseIdentifier(originalValue);
+ break;
+ case NamingConvention.InterfacePrefixUpperCamelCase:
+ newValue = GetInterfacePrefixUpperCamelCaseIdentifier(originalValue);
+ break;
+ default:
+ throw new ArgumentException(nameof(namingConvention));
+ }
+
+ return SyntaxFactory.Identifier(identifier.LeadingTrivia, newValue, identifier.TrailingTrivia);
+ }
+
+ // lowerCamelCase
+ private static string GetLowerCamelCaseIdentifier(string identifier)
+ {
+ if (ContainsSpecialCharacters(identifier))
+ {
+ return identifier;
+ }
+
+ var normalizedString = GetNormalizedString(identifier);
+
+ if (normalizedString.Length >= 1)
+ {
+ return char.ToLower(normalizedString[0]) + normalizedString.Substring(1);
+ }
+ return identifier;
+ }
+
+ // UpperCamelCase
+ private static string GetUpperCamelCaseIdentifier(string identifier)
+ {
+ if (ContainsSpecialCharacters(identifier))
+ {
+ return identifier;
+ }
+
+ var normalizedString = GetNormalizedString(identifier);
+
+ if (normalizedString.Length == 0)
+ {
+ return identifier;
+ }
+ return char.ToUpper(normalizedString[0]) + normalizedString.Substring(1);
+ }
+
+ // _lowerCamelCase
+ private static string GetUnderscoreLowerCamelCaseIdentifier(string identifier)
+ {
+ if (ContainsSpecialCharacters(identifier, '_'))
+ {
+ return identifier;
+ }
+
+ var normalizedString = GetNormalizedString(identifier);
+ if (normalizedString.Length == 0)
+ {
+ return identifier;
+ }
+
+ // Var
+ if (char.IsUpper(normalizedString[0]))
+ {
+ return "_" + char.ToLower(normalizedString[0]) + normalizedString.Substring(1);
+ }
+
+ // var
+ if (char.IsLower(normalizedString[0]))
+ {
+ return "_" + normalizedString;
+ }
+
+ return normalizedString;
+ }
+
+ // IInterface
+ private static string GetInterfacePrefixUpperCamelCaseIdentifier(string identifier)
+ {
+ if (ContainsSpecialCharacters(identifier))
+ {
+ return identifier;
+ }
+
+ var normalizedString = GetNormalizedString(identifier);
+
+ if (normalizedString.Length <= 1)
+ {
+ return identifier;
+ }
+
+ // iSomething
+ if (normalizedString[0] == 'i' && char.IsUpper(normalizedString[1]))
+ {
+ return "I" + normalizedString.Substring(1);
+ }
+
+ // isomething
+ if (char.IsLower(normalizedString[0]) && char.IsLower(normalizedString[1]))
+ {
+ return "I" + char.ToUpper(normalizedString[0]) + normalizedString.Substring(1);
+ }
+
+ // Isomething
+ if (normalizedString[0] == 'I' && char.IsLower(normalizedString[1]))
+ {
+ return "I" + char.ToUpper(normalizedString[1]) + normalizedString.Substring(2);
+ }
+
+ return normalizedString;
+ }
+
+ private static string GetNormalizedString(string input)
+ {
+ return new string(input.ToCharArray().Where(x => char.IsLetter(x) || char.IsNumber(x)).ToArray());
+ }
+
+ private static bool ContainsSpecialCharacters(string input, params char[] allowedCharacters)
+ {
+ return !input.ToCharArray().All(x => char.IsLetter(x) || char.IsNumber(x) || allowedCharacters.Contains(x));
+ }
}
}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/Utilities/NamingConvention.cs b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Utilities/NamingConvention.cs
new file mode 100644
index 0000000..2cce77c
--- /dev/null
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/Utilities/NamingConvention.cs
@@ -0,0 +1,10 @@
+namespace VSDiagnostics.Utilities
+{
+ public enum NamingConvention
+ {
+ UpperCamelCase,
+ LowerCamelCase,
+ UnderscoreLowerCamelCase,
+ InterfacePrefixUpperCamelCase
+ }
+}
\ No newline at end of file
diff --git a/VSDiagnostics/VSDiagnostics/VSDiagnostics/VSDiagnostics.csproj b/VSDiagnostics/VSDiagnostics/VSDiagnostics/VSDiagnostics.csproj
index ea83c7c..fb1ecd5 100644
--- a/VSDiagnostics/VSDiagnostics/VSDiagnostics/VSDiagnostics.csproj
+++ b/VSDiagnostics/VSDiagnostics/VSDiagnostics/VSDiagnostics.csproj
@@ -48,6 +48,8 @@
+
+
@@ -64,6 +66,7 @@
+