diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/IntelliTect.Analyzer.Tests.csproj b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/IntelliTect.Analyzer.Tests.csproj index 7e9f88e8..e47ec9e0 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/IntelliTect.Analyzer.Tests.csproj +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/IntelliTect.Analyzer.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0 + netcoreapp3.1 CA2007,CA1815,CA1303,CA1707,CA1305 diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/NamingFieldPascalUnderscoreTests.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/NamingFieldPascalUnderscoreTests.cs index 67b6fce9..fd4684b0 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/NamingFieldPascalUnderscoreTests.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/NamingFieldPascalUnderscoreTests.cs @@ -55,7 +55,6 @@ class NativeMethods VerifyCSharpDiagnostic(test); } - [TestMethod] public void FieldWithNamingViolation_FieldMissingLeadingUnderscore_Warning() { @@ -418,6 +417,41 @@ class TypeName VerifyCSharpDiagnostic(test); } + + [TestMethod] + [Description("Issue 80")] + public void FieldWithNamingViolation_FieldContainsUnderscore_Warning() + { + string test = @" + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + using System.Diagnostics; + + namespace ConsoleApplication1 + { + class TypeName + { + public string _My_Field; + } + }"; + var expected = new DiagnosticResult + { + Id = "INTL0001", + Message = "Field '_My_Field' should be named _PascalCase", + Severity = DiagnosticSeverity.Warning, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 13, 27) + } + }; + + VerifyCSharpDiagnostic(test, expected); + } + + protected override CodeFixProvider GetCSharpCodeFixProvider() { return new CodeFixes.NamingFieldPascalUnderscore(); diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/NamingMethodPascalTests.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/NamingMethodPascalTests.cs index 96e630ac..196a1c52 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/NamingMethodPascalTests.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/NamingMethodPascalTests.cs @@ -322,6 +322,45 @@ public class Views_Shared__ValidationScriptsPartial : global::Microsoft.AspNetCo VerifyCSharpDiagnostic(test); } + + [TestMethod] + [Description("Issue 80")] + public void MethodWithNamingViolation_MethodWithUnderscore_Warning() + { + string test = @" + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + using System.Diagnostics; + + namespace ConsoleApplication1 + { + class TypeName + { + public string My_Method() + { + return string.Empty; + } + } + }"; + var expected = new DiagnosticResult + { + Id = "INTL0003", + Message = "Method 'My_Method' should be PascalCase", + Severity = DiagnosticSeverity.Warning, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 13, 27) + } + }; + + VerifyCSharpDiagnostic(test, expected); + } + + + protected override CodeFixProvider GetCSharpCodeFixProvider() { return new CodeFixes.NamingIdentifierPascal(); diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/NamingPropertyPascalTests.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/NamingPropertyPascalTests.cs index bff5628f..ac4e4ba8 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/NamingPropertyPascalTests.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/NamingPropertyPascalTests.cs @@ -265,6 +265,40 @@ public class Views_Shared__ValidationScriptsPartial : global::Microsoft.AspNetCo VerifyCSharpDiagnostic(test); } + [TestMethod] + [Description("Issue 80")] + public void PropertyWithNamingViolation_PropertyContainsUnderscore_Warning() + { + string test = @" + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + using System.Diagnostics; + + namespace ConsoleApplication1 + { + class TypeName + { + public string My_Property { get; set; } + } + }"; + var expected = new DiagnosticResult + { + Id = "INTL0002", + Message = "Property 'My_Property' should be PascalCase", + Severity = DiagnosticSeverity.Warning, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 13, 27) + } + }; + + VerifyCSharpDiagnostic(test, expected); + } + + protected override CodeFixProvider GetCSharpCodeFixProvider() { return new CodeFixes.NamingIdentifierPascal(); diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/NamingFieldPascalUnderscore.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/NamingFieldPascalUnderscore.cs index b4f3380d..321f48d9 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/NamingFieldPascalUnderscore.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/NamingFieldPascalUnderscore.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Immutable; using System.Linq; +using IntelliTect.Analyzer.Naming; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -57,7 +58,7 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context) } if (namedTypeSymbol.Name.StartsWith("_", StringComparison.Ordinal) && namedTypeSymbol.Name.Length > 1 - && char.IsUpper(namedTypeSymbol.Name.Skip(1).First())) + && Casing.IsPascalCase(namedTypeSymbol.Name.Skip(1))) { return; } diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/NamingMethodPascal.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/NamingMethodPascal.cs index 7be0579d..d19c9f6f 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/NamingMethodPascal.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/NamingMethodPascal.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Immutable; using System.Linq; +using IntelliTect.Analyzer.Naming; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -66,7 +67,7 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context) return; } - if (char.IsUpper(namedTypeSymbol.Name.First())) + if (Casing.IsPascalCase(namedTypeSymbol.Name)) { return; } diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/NamingPropertyPascal.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/NamingPropertyPascal.cs index 23366e2c..2ace6cef 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/NamingPropertyPascal.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/NamingPropertyPascal.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Immutable; using System.Linq; +using IntelliTect.Analyzer.Naming; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -44,17 +45,17 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context) return; } - if (char.IsUpper(namedTypeSymbol.Name.First())) + if (namedTypeSymbol.ContainingType.IsNativeMethodsClass()) { return; } - if (namedTypeSymbol.ContainingType.IsNativeMethodsClass()) + if (namedTypeSymbol is IPropertySymbol property && property.IsIndexer) { return; } - if (namedTypeSymbol is IPropertySymbol property && property.IsIndexer) + if (Casing.IsPascalCase(namedTypeSymbol.Name)) { return; } diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer/Naming/Casing.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer/Naming/Casing.cs new file mode 100644 index 00000000..43c80ff0 --- /dev/null +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer/Naming/Casing.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace IntelliTect.Analyzer.Naming +{ + internal static class Casing + { + public static bool IsPascalCase(IEnumerable name) + { + bool isFirst = true; + foreach (char character in name) + { + if (isFirst && !char.IsUpper(character)) + { + return false; + } + + isFirst = false; + if (char.IsUpper(character) || + char.IsLower(character) || + char.IsNumber(character)) + { + continue; + } + return false; + } + return true; + } + } +} diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9ff35a76..20135109 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -14,6 +14,11 @@ pool: steps: +- task: UseDotNet@2 + inputs: + packageType: 'sdk' + version: '3.1.x' + - task: NuGetToolInstaller@0 displayName: 'Use latest NuGet'