From 75795f81138f99493af25e8b556ba4c2e0315aad Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 7 Dec 2020 11:12:09 -0800 Subject: [PATCH 1/3] Simplify tests for SA1649 --- .../SA1649CSharp9UnitTests.cs | 79 ---------------- .../DocumentationRules/SA1649UnitTests.cs | 94 ++++++++----------- 2 files changed, 37 insertions(+), 136 deletions(-) diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/DocumentationRules/SA1649CSharp9UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/DocumentationRules/SA1649CSharp9UnitTests.cs index b23bb8d7d..446a490b9 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/DocumentationRules/SA1649CSharp9UnitTests.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/DocumentationRules/SA1649CSharp9UnitTests.cs @@ -3,88 +3,9 @@ namespace StyleCop.Analyzers.Test.CSharp9.DocumentationRules { - using System.Collections.Generic; - using System.Threading.Tasks; - using Microsoft.CodeAnalysis.CSharp; using StyleCop.Analyzers.Test.CSharp8.DocumentationRules; - using Xunit; public class SA1649CSharp9UnitTests : SA1649CSharp8UnitTests { - public static IEnumerable CSharp9TypeKeywords - { - get - { - foreach (var keyword in TypeKeywords) - { - yield return keyword; - } - - yield return new object[] { "record", LanguageVersion.CSharp9 }; - } - } - - [Theory] - [MemberData(nameof(CSharp9TypeKeywords))] - public override async Task VerifyWrongFileNameAsync(string typeKeyword, LanguageVersion languageVersion) - { - await base.VerifyWrongFileNameAsync(typeKeyword, languageVersion).ConfigureAwait(false); - } - - [Theory] - [MemberData(nameof(CSharp9TypeKeywords))] - public override async Task VerifyWrongFileNameMultipleExtensionsAsync(string typeKeyword, LanguageVersion languageVersion) - { - await base.VerifyWrongFileNameMultipleExtensionsAsync(typeKeyword, languageVersion).ConfigureAwait(false); - } - - [Theory] - [MemberData(nameof(CSharp9TypeKeywords))] - public override async Task VerifyWrongFileNameNoExtensionAsync(string typeKeyword, LanguageVersion languageVersion) - { - await base.VerifyWrongFileNameNoExtensionAsync(typeKeyword, languageVersion).ConfigureAwait(false); - } - - [Theory] - [MemberData(nameof(CSharp9TypeKeywords))] - public override async Task VerifyCaseInsensitivityAsync(string typeKeyword, LanguageVersion languageVersion) - { - await base.VerifyCaseInsensitivityAsync(typeKeyword, languageVersion).ConfigureAwait(false); - } - - [Theory] - [MemberData(nameof(CSharp9TypeKeywords))] - public override async Task VerifyFirstTypeIsUsedAsync(string typeKeyword, LanguageVersion languageVersion) - { - await base.VerifyFirstTypeIsUsedAsync(typeKeyword, languageVersion).ConfigureAwait(false); - } - - [Theory] - [MemberData(nameof(CSharp9TypeKeywords))] - public override async Task VerifyThatPartialTypesAreIgnoredAsync(string typeKeyword, LanguageVersion languageVersion) - { - await base.VerifyThatPartialTypesAreIgnoredAsync(typeKeyword, languageVersion).ConfigureAwait(false); - } - - [Theory] - [MemberData(nameof(CSharp9TypeKeywords))] - public override async Task VerifyStyleCopNamingConventionForGenericTypeAsync(string typeKeyword, LanguageVersion languageVersion) - { - await base.VerifyStyleCopNamingConventionForGenericTypeAsync(typeKeyword, languageVersion).ConfigureAwait(false); - } - - [Theory] - [MemberData(nameof(CSharp9TypeKeywords))] - public override async Task VerifyMetadataNamingConventionForGenericTypeAsync(string typeKeyword, LanguageVersion languageVersion) - { - await base.VerifyMetadataNamingConventionForGenericTypeAsync(typeKeyword, languageVersion).ConfigureAwait(false); - } - - [Theory] - [MemberData(nameof(CSharp9TypeKeywords))] - public override async Task VerifyMetadataNamingConventionForGenericTypeMultipleExtensionsAsync(string typeKeyword, LanguageVersion languageVersion) - { - await base.VerifyMetadataNamingConventionForGenericTypeMultipleExtensionsAsync(typeKeyword, languageVersion).ConfigureAwait(false); - } } } diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1649UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1649UnitTests.cs index c0f9554a0..8306e9e22 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1649UnitTests.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1649UnitTests.cs @@ -3,12 +3,11 @@ namespace StyleCop.Analyzers.Test.DocumentationRules { - using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; - using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Testing; using StyleCop.Analyzers.DocumentationRules; + using StyleCop.Analyzers.Test.Helpers; using StyleCop.Analyzers.Test.Verifiers; using Xunit; using static StyleCop.Analyzers.Test.Verifiers.CustomDiagnosticVerifier; @@ -38,25 +37,14 @@ public class SA1649UnitTests } "; - public static IEnumerable TypeKeywords - { - get - { - yield return new object[] { "class", LanguageVersion.CSharp6 }; - yield return new object[] { "struct", LanguageVersion.CSharp6 }; - yield return new object[] { "interface", LanguageVersion.CSharp6 }; - } - } - /// /// Verifies that a wrong file name is correctly reported. /// /// The type keyword to use during the test. - /// The language version to test with. /// A representing the asynchronous unit test. [Theory] - [MemberData(nameof(TypeKeywords))] - public virtual async Task VerifyWrongFileNameAsync(string typeKeyword, LanguageVersion languageVersion) + [MemberData(nameof(CommonMemberData.TypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + public async Task VerifyWrongFileNameAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ @@ -75,7 +63,7 @@ public virtual async Task VerifyWrongFileNameAsync(string typeKeyword, LanguageV "; var expectedDiagnostic = Diagnostic().WithLocation("WrongFileName.cs", 3, 13 + typeKeyword.Length); - await VerifyCSharpFixAsync(languageVersion, "WrongFileName.cs", testCode, StyleCopSettings, expectedDiagnostic, "TestType.cs", fixedCode, CancellationToken.None).ConfigureAwait(false); + await VerifyCSharpFixAsync("WrongFileName.cs", testCode, StyleCopSettings, expectedDiagnostic, "TestType.cs", fixedCode, CancellationToken.None).ConfigureAwait(false); } /// @@ -83,11 +71,10 @@ public virtual async Task VerifyWrongFileNameAsync(string typeKeyword, LanguageV /// regression test for DotNetAnalyzers/StyleCopAnalyzers#1829. /// /// The type keyword to use during the test. - /// The language version to test with. /// A representing the asynchronous unit test. [Theory] - [MemberData(nameof(TypeKeywords))] - public virtual async Task VerifyWrongFileNameMultipleExtensionsAsync(string typeKeyword, LanguageVersion languageVersion) + [MemberData(nameof(CommonMemberData.TypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + public async Task VerifyWrongFileNameMultipleExtensionsAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ @@ -106,7 +93,7 @@ public virtual async Task VerifyWrongFileNameMultipleExtensionsAsync(string type "; var expectedDiagnostic = Diagnostic().WithLocation("WrongFileName.svc.cs", 3, 13 + typeKeyword.Length); - await VerifyCSharpFixAsync(languageVersion, "WrongFileName.svc.cs", testCode, StyleCopSettings, expectedDiagnostic, "TestType.svc.cs", fixedCode, CancellationToken.None).ConfigureAwait(false); + await VerifyCSharpFixAsync("WrongFileName.svc.cs", testCode, StyleCopSettings, expectedDiagnostic, "TestType.svc.cs", fixedCode, CancellationToken.None).ConfigureAwait(false); } /// @@ -114,11 +101,10 @@ public virtual async Task VerifyWrongFileNameMultipleExtensionsAsync(string type /// for DotNetAnalyzers/StyleCopAnalyzers#1829. /// /// The type keyword to use during the test. - /// The language version to test with. /// A representing the asynchronous unit test. [Theory] - [MemberData(nameof(TypeKeywords))] - public virtual async Task VerifyWrongFileNameNoExtensionAsync(string typeKeyword, LanguageVersion languageVersion) + [MemberData(nameof(CommonMemberData.TypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + public async Task VerifyWrongFileNameNoExtensionAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ @@ -137,18 +123,17 @@ public virtual async Task VerifyWrongFileNameNoExtensionAsync(string typeKeyword "; var expectedDiagnostic = Diagnostic().WithLocation("WrongFileName", 3, 13 + typeKeyword.Length); - await VerifyCSharpFixAsync(languageVersion, "WrongFileName", testCode, StyleCopSettings, expectedDiagnostic, "TestType", fixedCode, CancellationToken.None).ConfigureAwait(false); + await VerifyCSharpFixAsync("WrongFileName", testCode, StyleCopSettings, expectedDiagnostic, "TestType", fixedCode, CancellationToken.None).ConfigureAwait(false); } /// /// Verifies that the file name is not case sensitive. /// /// The type keyword to use during the test. - /// The language version to test with. /// A representing the asynchronous unit test. [Theory] - [MemberData(nameof(TypeKeywords))] - public virtual async Task VerifyCaseInsensitivityAsync(string typeKeyword, LanguageVersion languageVersion) + [MemberData(nameof(CommonMemberData.TypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + public async Task VerifyCaseInsensitivityAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ @@ -158,18 +143,17 @@ public virtual async Task VerifyCaseInsensitivityAsync(string typeKeyword, Langu }} "; - await VerifyCSharpDiagnosticAsync(languageVersion, "testtype.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + await VerifyCSharpDiagnosticAsync("testtype.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); } /// /// Verifies that the file name is based on the first type. /// /// The type keyword to use during the test. - /// The language version to test with. /// A representing the asynchronous unit test. [Theory] - [MemberData(nameof(TypeKeywords))] - public virtual async Task VerifyFirstTypeIsUsedAsync(string typeKeyword, LanguageVersion languageVersion) + [MemberData(nameof(CommonMemberData.TypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + public async Task VerifyFirstTypeIsUsedAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ @@ -183,18 +167,17 @@ public virtual async Task VerifyFirstTypeIsUsedAsync(string typeKeyword, Languag }} "; - await VerifyCSharpDiagnosticAsync(languageVersion, "TestType.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + await VerifyCSharpDiagnosticAsync("TestType.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); } /// /// Verifies that partial types are ignored. /// /// The type keyword to use during the test. - /// The language version to test with. /// A representing the asynchronous unit test. [Theory] - [MemberData(nameof(TypeKeywords))] - public virtual async Task VerifyThatPartialTypesAreIgnoredAsync(string typeKeyword, LanguageVersion languageVersion) + [MemberData(nameof(CommonMemberData.TypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + public async Task VerifyThatPartialTypesAreIgnoredAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ @@ -204,18 +187,17 @@ public partial {typeKeyword} TestType }} "; - await VerifyCSharpDiagnosticAsync(languageVersion, "WrongFileName.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + await VerifyCSharpDiagnosticAsync("WrongFileName.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); } /// /// Verifies that the StyleCop file name convention for a generic type is handled correctly. /// /// The type keyword to use during the test. - /// The language version to test with. /// A representing the asynchronous unit test. [Theory] - [MemberData(nameof(TypeKeywords))] - public virtual async Task VerifyStyleCopNamingConventionForGenericTypeAsync(string typeKeyword, LanguageVersion languageVersion) + [MemberData(nameof(CommonMemberData.TypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + public async Task VerifyStyleCopNamingConventionForGenericTypeAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ @@ -226,19 +208,18 @@ public virtual async Task VerifyStyleCopNamingConventionForGenericTypeAsync(stri "; var expectedDiagnostic = Diagnostic().WithLocation("TestType`3.cs", 3, 13 + typeKeyword.Length); - await VerifyCSharpDiagnosticAsync(languageVersion, "TestType.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); - await VerifyCSharpFixAsync(languageVersion, "TestType`3.cs", testCode, StyleCopSettings, expectedDiagnostic, "TestType{T1,T2,T3}.cs", testCode, CancellationToken.None).ConfigureAwait(false); + await VerifyCSharpDiagnosticAsync("TestType.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + await VerifyCSharpFixAsync("TestType`3.cs", testCode, StyleCopSettings, expectedDiagnostic, "TestType{T1,T2,T3}.cs", testCode, CancellationToken.None).ConfigureAwait(false); } /// /// Verifies that the metadata file name convention for a generic type is handled correctly. /// /// The type keyword to use during the test. - /// The language version to test with. /// A representing the asynchronous unit test. [Theory] - [MemberData(nameof(TypeKeywords))] - public virtual async Task VerifyMetadataNamingConventionForGenericTypeAsync(string typeKeyword, LanguageVersion languageVersion) + [MemberData(nameof(CommonMemberData.TypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + public async Task VerifyMetadataNamingConventionForGenericTypeAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ @@ -249,10 +230,10 @@ public virtual async Task VerifyMetadataNamingConventionForGenericTypeAsync(stri "; var expectedDiagnostic = Diagnostic().WithLocation("TestType{T1,T2,T3}.cs", 3, 13 + typeKeyword.Length); - await VerifyCSharpFixAsync(languageVersion, "TestType{T1,T2,T3}.cs", testCode, MetadataSettings, expectedDiagnostic, "TestType`3.cs", testCode, CancellationToken.None).ConfigureAwait(false); + await VerifyCSharpFixAsync("TestType{T1,T2,T3}.cs", testCode, MetadataSettings, expectedDiagnostic, "TestType`3.cs", testCode, CancellationToken.None).ConfigureAwait(false); expectedDiagnostic = Diagnostic().WithLocation("TestType.cs", 3, 13 + typeKeyword.Length); - await VerifyCSharpFixAsync(languageVersion, "TestType.cs", testCode, MetadataSettings, expectedDiagnostic, "TestType`3.cs", testCode, CancellationToken.None).ConfigureAwait(false); + await VerifyCSharpFixAsync("TestType.cs", testCode, MetadataSettings, expectedDiagnostic, "TestType`3.cs", testCode, CancellationToken.None).ConfigureAwait(false); } /// @@ -260,11 +241,10 @@ public virtual async Task VerifyMetadataNamingConventionForGenericTypeAsync(stri /// regression test for DotNetAnalyzers/StyleCopAnalyzers#1829. /// /// The type keyword to use during the test. - /// The language version to test with. /// A representing the asynchronous unit test. [Theory] - [MemberData(nameof(TypeKeywords))] - public virtual async Task VerifyMetadataNamingConventionForGenericTypeMultipleExtensionsAsync(string typeKeyword, LanguageVersion languageVersion) + [MemberData(nameof(CommonMemberData.TypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + public async Task VerifyMetadataNamingConventionForGenericTypeMultipleExtensionsAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ @@ -283,7 +263,7 @@ public virtual async Task VerifyMetadataNamingConventionForGenericTypeMultipleEx "; var expectedDiagnostic = Diagnostic().WithLocation("TestType.svc.cs", 3, 13 + typeKeyword.Length); - await VerifyCSharpFixAsync(languageVersion, "TestType.svc.cs", testCode, MetadataSettings, expectedDiagnostic, "TestType`1.svc.cs", fixedCode, CancellationToken.None).ConfigureAwait(false); + await VerifyCSharpFixAsync("TestType.svc.cs", testCode, MetadataSettings, expectedDiagnostic, "TestType`1.svc.cs", fixedCode, CancellationToken.None).ConfigureAwait(false); } /// @@ -298,12 +278,12 @@ public async Task VerifyWithoutFirstTypeAsync() } "; - await VerifyCSharpDiagnosticAsync(LanguageVersion.CSharp6, "Test0.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + await VerifyCSharpDiagnosticAsync("Test0.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); } - internal static Task VerifyCSharpDiagnosticAsync(LanguageVersion languageVersion, string fileName, string source, DiagnosticResult[] expected, CancellationToken cancellationToken) + private static Task VerifyCSharpDiagnosticAsync(string fileName, string source, DiagnosticResult[] expected, CancellationToken cancellationToken) { - var test = new StyleCopCodeFixVerifier.CSharpTest(languageVersion) + var test = new StyleCopCodeFixVerifier.CSharpTest() { TestSources = { (fileName, source) }, }; @@ -312,12 +292,12 @@ internal static Task VerifyCSharpDiagnosticAsync(LanguageVersion languageVersion return test.RunAsync(cancellationToken); } - internal static Task VerifyCSharpFixAsync(LanguageVersion languageVersion, string oldFileName, string source, string testSettings, DiagnosticResult expected, string newFileName, string fixedSource, CancellationToken cancellationToken) - => VerifyCSharpFixAsync(languageVersion, oldFileName, source, testSettings, new[] { expected }, newFileName, fixedSource, cancellationToken); + private static Task VerifyCSharpFixAsync(string oldFileName, string source, string testSettings, DiagnosticResult expected, string newFileName, string fixedSource, CancellationToken cancellationToken) + => VerifyCSharpFixAsync(oldFileName, source, testSettings, new[] { expected }, newFileName, fixedSource, cancellationToken); - internal static Task VerifyCSharpFixAsync(LanguageVersion languageVersion, string oldFileName, string source, string testSettings, DiagnosticResult[] expected, string newFileName, string fixedSource, CancellationToken cancellationToken) + private static Task VerifyCSharpFixAsync(string oldFileName, string source, string testSettings, DiagnosticResult[] expected, string newFileName, string fixedSource, CancellationToken cancellationToken) { - var test = new StyleCopCodeFixVerifier.CSharpTest(languageVersion) + var test = new StyleCopCodeFixVerifier.CSharpTest() { TestSources = { (oldFileName, source) }, FixedSources = { (newFileName, fixedSource) }, From 8056de64241f285860615536087ff15c2788f250 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 7 Dec 2020 11:15:45 -0800 Subject: [PATCH 2/3] Use markup syntax for SA1649 tests --- .../DocumentationRules/SA1649UnitTests.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1649UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1649UnitTests.cs index 8306e9e22..040b76390 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1649UnitTests.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1649UnitTests.cs @@ -48,7 +48,7 @@ public async Task VerifyWrongFileNameAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ - public {typeKeyword} TestType + public {typeKeyword} {{|#0:TestType|}} {{ }} }} @@ -62,7 +62,7 @@ public async Task VerifyWrongFileNameAsync(string typeKeyword) }} "; - var expectedDiagnostic = Diagnostic().WithLocation("WrongFileName.cs", 3, 13 + typeKeyword.Length); + var expectedDiagnostic = Diagnostic().WithLocation(0); await VerifyCSharpFixAsync("WrongFileName.cs", testCode, StyleCopSettings, expectedDiagnostic, "TestType.cs", fixedCode, CancellationToken.None).ConfigureAwait(false); } @@ -78,7 +78,7 @@ public async Task VerifyWrongFileNameMultipleExtensionsAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ - public {typeKeyword} TestType + public {typeKeyword} {{|#0:TestType|}} {{ }} }} @@ -92,7 +92,7 @@ public async Task VerifyWrongFileNameMultipleExtensionsAsync(string typeKeyword) }} "; - var expectedDiagnostic = Diagnostic().WithLocation("WrongFileName.svc.cs", 3, 13 + typeKeyword.Length); + var expectedDiagnostic = Diagnostic().WithLocation(0); await VerifyCSharpFixAsync("WrongFileName.svc.cs", testCode, StyleCopSettings, expectedDiagnostic, "TestType.svc.cs", fixedCode, CancellationToken.None).ConfigureAwait(false); } @@ -108,7 +108,7 @@ public async Task VerifyWrongFileNameNoExtensionAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ - public {typeKeyword} TestType + public {typeKeyword} {{|#0:TestType|}} {{ }} }} @@ -122,7 +122,7 @@ public async Task VerifyWrongFileNameNoExtensionAsync(string typeKeyword) }} "; - var expectedDiagnostic = Diagnostic().WithLocation("WrongFileName", 3, 13 + typeKeyword.Length); + var expectedDiagnostic = Diagnostic().WithLocation(0); await VerifyCSharpFixAsync("WrongFileName", testCode, StyleCopSettings, expectedDiagnostic, "TestType", fixedCode, CancellationToken.None).ConfigureAwait(false); } @@ -201,13 +201,13 @@ public async Task VerifyStyleCopNamingConventionForGenericTypeAsync(string typeK { var testCode = $@"namespace TestNamespace {{ - public {typeKeyword} TestType + public {typeKeyword} {{|#0:TestType|}} {{ }} }} "; - var expectedDiagnostic = Diagnostic().WithLocation("TestType`3.cs", 3, 13 + typeKeyword.Length); + var expectedDiagnostic = Diagnostic().WithLocation(0); await VerifyCSharpDiagnosticAsync("TestType.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); await VerifyCSharpFixAsync("TestType`3.cs", testCode, StyleCopSettings, expectedDiagnostic, "TestType{T1,T2,T3}.cs", testCode, CancellationToken.None).ConfigureAwait(false); } @@ -223,16 +223,16 @@ public async Task VerifyMetadataNamingConventionForGenericTypeAsync(string typeK { var testCode = $@"namespace TestNamespace {{ - public {typeKeyword} TestType + public {typeKeyword} {{|#0:TestType|}} {{ }} }} "; - var expectedDiagnostic = Diagnostic().WithLocation("TestType{T1,T2,T3}.cs", 3, 13 + typeKeyword.Length); + var expectedDiagnostic = Diagnostic().WithLocation(0); await VerifyCSharpFixAsync("TestType{T1,T2,T3}.cs", testCode, MetadataSettings, expectedDiagnostic, "TestType`3.cs", testCode, CancellationToken.None).ConfigureAwait(false); - expectedDiagnostic = Diagnostic().WithLocation("TestType.cs", 3, 13 + typeKeyword.Length); + expectedDiagnostic = Diagnostic().WithLocation(0); await VerifyCSharpFixAsync("TestType.cs", testCode, MetadataSettings, expectedDiagnostic, "TestType`3.cs", testCode, CancellationToken.None).ConfigureAwait(false); } @@ -248,7 +248,7 @@ public async Task VerifyMetadataNamingConventionForGenericTypeMultipleExtensions { var testCode = $@"namespace TestNamespace {{ - public {typeKeyword} TestType + public {typeKeyword} {{|#0:TestType|}} {{ }} }} @@ -262,7 +262,7 @@ public async Task VerifyMetadataNamingConventionForGenericTypeMultipleExtensions }} "; - var expectedDiagnostic = Diagnostic().WithLocation("TestType.svc.cs", 3, 13 + typeKeyword.Length); + var expectedDiagnostic = Diagnostic().WithLocation(0); await VerifyCSharpFixAsync("TestType.svc.cs", testCode, MetadataSettings, expectedDiagnostic, "TestType`1.svc.cs", fixedCode, CancellationToken.None).ConfigureAwait(false); } From 37a0ba29c83c8eb990cbd87deacbd760464c0b1d Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 7 Dec 2020 11:42:17 -0800 Subject: [PATCH 3/3] Check file name for single 'enum' and 'delegate' top-level types Closes #3234 --- .../DocumentationRules/SA1649UnitTests.cs | 101 +++++++++++++----- .../Helpers/CommonMemberData.cs | 9 ++ .../SA1649FileNameMustMatchTypeName.cs | 25 ++++- 3 files changed, 103 insertions(+), 32 deletions(-) diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1649UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1649UnitTests.cs index 040b76390..13dc67ade 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1649UnitTests.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1649UnitTests.cs @@ -43,22 +43,18 @@ public class SA1649UnitTests /// The type keyword to use during the test. /// A representing the asynchronous unit test. [Theory] - [MemberData(nameof(CommonMemberData.TypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + [MemberData(nameof(CommonMemberData.AllTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task VerifyWrongFileNameAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ - public {typeKeyword} {{|#0:TestType|}} - {{ - }} + {GetTypeDeclaration(typeKeyword, "TestType", diagnosticKey: 0)} }} "; var fixedCode = $@"namespace TestNamespace {{ - public {typeKeyword} TestType - {{ - }} + {GetTypeDeclaration(typeKeyword, "TestType")} }} "; @@ -73,22 +69,18 @@ public async Task VerifyWrongFileNameAsync(string typeKeyword) /// The type keyword to use during the test. /// A representing the asynchronous unit test. [Theory] - [MemberData(nameof(CommonMemberData.TypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + [MemberData(nameof(CommonMemberData.AllTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task VerifyWrongFileNameMultipleExtensionsAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ - public {typeKeyword} {{|#0:TestType|}} - {{ - }} + {GetTypeDeclaration(typeKeyword, "TestType", diagnosticKey: 0)} }} "; var fixedCode = $@"namespace TestNamespace {{ - public {typeKeyword} TestType - {{ - }} + {GetTypeDeclaration(typeKeyword, "TestType")} }} "; @@ -103,22 +95,18 @@ public async Task VerifyWrongFileNameMultipleExtensionsAsync(string typeKeyword) /// The type keyword to use during the test. /// A representing the asynchronous unit test. [Theory] - [MemberData(nameof(CommonMemberData.TypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + [MemberData(nameof(CommonMemberData.AllTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task VerifyWrongFileNameNoExtensionAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ - public {typeKeyword} {{|#0:TestType|}} - {{ - }} + {GetTypeDeclaration(typeKeyword, "TestType", diagnosticKey: 0)} }} "; var fixedCode = $@"namespace TestNamespace {{ - public {typeKeyword} TestType - {{ - }} + {GetTypeDeclaration(typeKeyword, "TestType")} }} "; @@ -132,14 +120,12 @@ public async Task VerifyWrongFileNameNoExtensionAsync(string typeKeyword) /// The type keyword to use during the test. /// A representing the asynchronous unit test. [Theory] - [MemberData(nameof(CommonMemberData.TypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + [MemberData(nameof(CommonMemberData.AllTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task VerifyCaseInsensitivityAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ - public {typeKeyword} TestType - {{ - }} + {GetTypeDeclaration(typeKeyword, "TestType")} }} "; @@ -157,17 +143,62 @@ public async Task VerifyFirstTypeIsUsedAsync(string typeKeyword) { var testCode = $@"namespace TestNamespace {{ - public {typeKeyword} TestType + public enum IgnoredEnum {{ }} + public delegate void IgnoredDelegate(); + + {GetTypeDeclaration(typeKeyword, "TestType", diagnosticKey: 0)} + + {GetTypeDeclaration(typeKeyword, "TestType2")} +}} +"; + var fixedCode = $@"namespace TestNamespace +{{ + public enum IgnoredEnum {{ }} + public delegate void IgnoredDelegate(); + + {GetTypeDeclaration(typeKeyword, "TestType")} + + {GetTypeDeclaration(typeKeyword, "TestType2")} +}} +"; + + var expectedDiagnostic = Diagnostic().WithLocation(0); + await VerifyCSharpFixAsync("TestType2.cs", testCode, StyleCopSettings, expectedDiagnostic, "TestType.cs", fixedCode, CancellationToken.None).ConfigureAwait(false); + } + + [Fact] + [WorkItem(3234, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3234")] + public async Task VerifyMultipleEnumTypesIgnoredAsync() + { + var testCode = $@"namespace TestNamespace +{{ + public enum TestType {{ }} - public {typeKeyword} TestType2 + public enum TestType2 {{ }} }} "; - await VerifyCSharpDiagnosticAsync("TestType.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + // File names are not checked for 'enum' if more than one is present + await VerifyCSharpDiagnosticAsync("TestType2.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + } + + [Fact] + [WorkItem(3234, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3234")] + public async Task VerifyMultipleDelegateTypesIgnoredAsync() + { + var testCode = $@"namespace TestNamespace +{{ + public delegate void TestType(); + public delegate void TestType2(); +}} +"; + + // File names are not checked for 'delegate' if more than one is present + await VerifyCSharpDiagnosticAsync("TestType2.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); } /// @@ -281,6 +312,20 @@ public async Task VerifyWithoutFirstTypeAsync() await VerifyCSharpDiagnosticAsync("Test0.cs", testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); } + private static string GetTypeDeclaration(string typeKind, string typeName, int? diagnosticKey = null) + { + if (diagnosticKey is not null) + { + typeName = $"{{|#{diagnosticKey}:{typeName}|}}"; + } + + return typeKind switch + { + "delegate" => $"public delegate void {typeName}();", + _ => $"public {typeKind} {typeName} {{ }}", + }; + } + private static Task VerifyCSharpDiagnosticAsync(string fileName, string source, DiagnosticResult[] expected, CancellationToken cancellationToken) { var test = new StyleCopCodeFixVerifier.CSharpTest() diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/Helpers/CommonMemberData.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/Helpers/CommonMemberData.cs index 92f3d655d..eb74fdfc0 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/Helpers/CommonMemberData.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/Helpers/CommonMemberData.cs @@ -39,5 +39,14 @@ public static IEnumerable BaseTypeDeclarationKeywords .Concat(new[] { new[] { "enum" } }); } } + + public static IEnumerable AllTypeDeclarationKeywords + { + get + { + return BaseTypeDeclarationKeywords + .Concat(new[] { new[] { "delegate" } }); + } + } } } diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1649FileNameMustMatchTypeName.cs b/StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1649FileNameMustMatchTypeName.cs index f4fd14256..125fc6e4d 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1649FileNameMustMatchTypeName.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1649FileNameMustMatchTypeName.cs @@ -67,7 +67,8 @@ public static void HandleSyntaxTree(SyntaxTreeAnalysisContext context, StyleCopS return; } - if (firstTypeDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword)) + var modifiers = (firstTypeDeclaration as BaseTypeDeclarationSyntax)?.Modifiers ?? SyntaxFactory.TokenList(); + if (modifiers.Any(SyntaxKind.PartialKeyword)) { return; } @@ -87,15 +88,31 @@ public static void HandleSyntaxTree(SyntaxTreeAnalysisContext context, StyleCopS var properties = ImmutableDictionary.Create() .Add(ExpectedFileNameKey, expectedFileName + suffix); - context.ReportDiagnostic(Diagnostic.Create(Descriptor, firstTypeDeclaration.Identifier.GetLocation(), properties)); + var identifier = (firstTypeDeclaration as BaseTypeDeclarationSyntax)?.Identifier + ?? ((DelegateDeclarationSyntax)firstTypeDeclaration).Identifier; + context.ReportDiagnostic(Diagnostic.Create(Descriptor, identifier.GetLocation(), properties)); } } - private static TypeDeclarationSyntax GetFirstTypeDeclaration(SyntaxNode root) + private static MemberDeclarationSyntax GetFirstTypeDeclaration(SyntaxNode root) { - return root.DescendantNodes(descendIntoChildren: node => node.IsKind(SyntaxKind.CompilationUnit) || node.IsKind(SyntaxKind.NamespaceDeclaration)) + // Prefer to find the first type which is a true TypeDeclarationSyntax + MemberDeclarationSyntax firstTypeDeclaration = root.DescendantNodes(descendIntoChildren: node => node.IsKind(SyntaxKind.CompilationUnit) || node.IsKind(SyntaxKind.NamespaceDeclaration)) .OfType() .FirstOrDefault(); + + // If no TypeDeclarationSyntax is found, expand the search to any type declaration as long as only one + // is present + var expandedTypeDeclarations = root.DescendantNodes(descendIntoChildren: node => node.IsKind(SyntaxKind.CompilationUnit) || node.IsKind(SyntaxKind.NamespaceDeclaration)) + .OfType() + .Where(node => node is BaseTypeDeclarationSyntax || node.IsKind(SyntaxKind.DelegateDeclaration)) + .ToList(); + if (expandedTypeDeclarations.Count == 1) + { + firstTypeDeclaration = expandedTypeDeclarations[0]; + } + + return firstTypeDeclaration; } } }