Skip to content

Commit 3ca55e3

Browse files
committed
Merge branch 'master' into issue2575
2 parents 50a5fbf + 73f64f7 commit 3ca55e3

10 files changed

Lines changed: 154 additions & 55 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/DocumentationRules/SA1648CSharp11UnitTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,46 @@
33

44
namespace StyleCop.Analyzers.Test.CSharp11.DocumentationRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp10.DocumentationRules;
10+
using Xunit;
711

812
public partial class SA1648CSharp11UnitTests : SA1648CSharp10UnitTests
913
{
14+
[WorkItem(3595, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3595")]
15+
[Theory]
16+
[InlineData("abstract void TestMethod();", "public void TestMethod() {}")]
17+
[InlineData("abstract void TestMethod();", "void TestInterface.TestMethod() {}")]
18+
[InlineData("virtual void TestMethod() {}", "public void TestMethod() {}")]
19+
[InlineData("virtual void TestMethod() {}", "void TestInterface.TestMethod() {}")]
20+
[InlineData("abstract int TestProperty { get; set; }", "public int TestProperty { get; set; }")]
21+
[InlineData("abstract int TestProperty { get; set; }", "int TestInterface.TestProperty { get; set; }")]
22+
[InlineData("virtual int TestProperty { get; set; }", "public int TestProperty { get; set; }")]
23+
[InlineData("virtual int TestProperty { get; set; }", "int TestInterface.TestProperty { get; set; }")]
24+
[InlineData("abstract event System.Action TestEvent;", "public event System.Action TestEvent;")]
25+
[InlineData("abstract event System.Action TestEvent;", "event System.Action TestInterface.TestEvent { add {} remove {} }")]
26+
[InlineData("virtual event System.Action TestEvent;", "public event System.Action TestEvent;")]
27+
[InlineData("virtual event System.Action TestEvent;", "event System.Action TestInterface.TestEvent { add {} remove {} }")]
28+
public async Task TestCorrectMemberInheritDocFromStaticAbstractOrVirtualMemberInInterfaceAsync(string interfaceMember, string classMember)
29+
{
30+
var testCode = $@"
31+
public interface TestInterface
32+
{{
33+
/// <summary>
34+
/// A summary text.
35+
/// </summary>
36+
static {interfaceMember}
37+
}}
38+
39+
public class TestClass : TestInterface
40+
{{
41+
/// <inheritdoc />
42+
static {classMember}
43+
}}";
44+
45+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
46+
}
1047
}
1148
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/MaintainabilityRules/SA1119CSharp7UnitTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55

66
namespace StyleCop.Analyzers.Test.CSharp7.MaintainabilityRules
77
{
8+
using System.Collections.Generic;
89
using System.Threading;
910
using System.Threading.Tasks;
1011
using Microsoft.CodeAnalysis.Testing;
12+
using StyleCop.Analyzers.Lightup;
13+
using StyleCop.Analyzers.Test.Helpers;
1114
using StyleCop.Analyzers.Test.MaintainabilityRules;
1215
using Xunit;
1316
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
@@ -16,6 +19,31 @@ namespace StyleCop.Analyzers.Test.CSharp7.MaintainabilityRules
1619

1720
public partial class SA1119CSharp7UnitTests : SA1119UnitTests
1821
{
22+
public static IEnumerable<object[]> Assignments
23+
{
24+
get
25+
{
26+
yield return new object[] { "= 1" };
27+
yield return new object[] { "+= 1" };
28+
yield return new object[] { "-= 1" };
29+
yield return new object[] { "*= 1" };
30+
yield return new object[] { "/= 1" };
31+
yield return new object[] { "%= 1" };
32+
yield return new object[] { "&= 1" };
33+
yield return new object[] { "|= 1" };
34+
yield return new object[] { "^= 1" };
35+
yield return new object[] { "<<= 1" };
36+
yield return new object[] { ">>= 1" };
37+
yield return new object[] { "++" };
38+
yield return new object[] { "--" };
39+
40+
if (LightupHelpers.SupportsCSharp11)
41+
{
42+
yield return new object[] { ">>>= 1" };
43+
}
44+
}
45+
}
46+
1947
/// <summary>
2048
/// Verifies that extra parentheses in pattern matching is not reported.
2149
/// </summary>
@@ -85,5 +113,21 @@ public void Bar()
85113

86114
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
87115
}
116+
117+
[Theory]
118+
[MemberData(nameof(Assignments))]
119+
[WorkItem(3712, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3712")]
120+
public async Task TestConditionalRefAssignmentAsync(string assignment)
121+
{
122+
var testCode = $@"public class Foo
123+
{{
124+
public void Bar(bool b, ref int x, ref int y)
125+
{{
126+
(b ? ref x : ref y) {assignment};
127+
}}
128+
}}";
129+
130+
await VerifyCSharpDiagnosticAsync(LanguageVersionEx.CSharp7_2.OrLaterDefault(), testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
131+
}
88132
}
89133
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp8/DocumentationRules/SA1648CSharp8UnitTests.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,37 @@
33

44
namespace StyleCop.Analyzers.Test.CSharp8.DocumentationRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp7.DocumentationRules;
10+
using Xunit;
711

812
public partial class SA1648CSharp8UnitTests : SA1648CSharp7UnitTests
913
{
14+
[WorkItem(3595, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3595")]
15+
[Theory]
16+
[InlineData("void TestMethod() {}")]
17+
[InlineData("int TestProperty { get; set; }")]
18+
[InlineData("event System.Action TestEvent;")]
19+
public async Task TestIncorrectMemberInheritDocFromStaticMemberInInterfaceAsync(string member)
20+
{
21+
var testCode = $@"
22+
public interface TestInterface
23+
{{
24+
/// <summary>
25+
/// A summary text.
26+
/// </summary>
27+
static {member}
28+
}}
29+
30+
public class TestClass : TestInterface
31+
{{
32+
/// [|<inheritdoc />|]
33+
public static {member}
34+
}}";
35+
36+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
37+
}
1038
}
1139
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp8/MaintainabilityRules/SA1119CSharp8UnitTests.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,25 @@ public unsafe string TestMethod(int n, byte* a, byte* b)
219219
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
220220
}
221221

222+
[Fact]
223+
[WorkItem(3730, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3730")]
224+
public async Task TestSwitchExpressionFollowedByInvocationAsync()
225+
{
226+
string testCode = @"
227+
using System;
228+
229+
public class Foo
230+
{
231+
public string TestMethod(int n, Func<string> a, Func<string> b)
232+
{
233+
return (n switch { 1 => a, 2 => b })();
234+
}
235+
}
236+
";
237+
238+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
239+
}
240+
222241
[Fact]
223242
public async Task TestStackAllocExpressionInExpressionAsync()
224243
{

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1600UnitTests.cs

Lines changed: 10 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace StyleCop.Analyzers.Test.DocumentationRules
1010
using Microsoft.CodeAnalysis.CSharp;
1111
using Microsoft.CodeAnalysis.Testing;
1212
using StyleCop.Analyzers.DocumentationRules;
13+
using StyleCop.Analyzers.Test.Helpers;
1314
using Xunit;
1415
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
1516
StyleCop.Analyzers.DocumentationRules.SA1600ElementsMustBeDocumented,
@@ -40,52 +41,19 @@ public async Task TestRegressionMethodGlobalNamespaceAsync(string code)
4041
await VerifyCSharpDiagnosticAsync(this.LanguageVersion, testCode, expected, CancellationToken.None).ConfigureAwait(false);
4142
}
4243

43-
[Fact]
44-
public async Task TestClassWithoutDocumentationAsync()
45-
{
46-
await this.TestTypeWithoutDocumentationAsync("class", false).ConfigureAwait(false);
47-
}
48-
49-
[Fact]
50-
public async Task TestStructWithoutDocumentationAsync()
51-
{
52-
await this.TestTypeWithoutDocumentationAsync("struct", false).ConfigureAwait(false);
53-
}
54-
55-
[Fact]
56-
public async Task TestEnumWithoutDocumentationAsync()
57-
{
58-
await this.TestTypeWithoutDocumentationAsync("enum", false).ConfigureAwait(false);
59-
}
60-
61-
[Fact]
62-
public async Task TestInterfaceWithoutDocumentationAsync()
63-
{
64-
await this.TestTypeWithoutDocumentationAsync("interface", true).ConfigureAwait(false);
65-
}
66-
67-
[Fact]
68-
public async Task TestClassWithDocumentationAsync()
69-
{
70-
await this.TestTypeWithDocumentationAsync("class").ConfigureAwait(false);
71-
}
72-
73-
[Fact]
74-
public async Task TestStructWithDocumentationAsync()
75-
{
76-
await this.TestTypeWithDocumentationAsync("struct").ConfigureAwait(false);
77-
}
78-
79-
[Fact]
80-
public async Task TestEnumWithDocumentationAsync()
44+
[Theory]
45+
[MemberData(nameof(CommonMemberData.BaseTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))]
46+
public async Task TestBaseTypeWithoutDocumentationAsync(string type)
8147
{
82-
await this.TestTypeWithDocumentationAsync("enum").ConfigureAwait(false);
48+
var isInterface = type == "interface";
49+
await this.TestTypeWithoutDocumentationAsync(type, isInterface).ConfigureAwait(false);
8350
}
8451

85-
[Fact]
86-
public async Task TestInterfaceWithDocumentationAsync()
52+
[Theory]
53+
[MemberData(nameof(CommonMemberData.BaseTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))]
54+
public async Task TestBaseTypeWithDocumentationAsync(string type)
8755
{
88-
await this.TestTypeWithDocumentationAsync("interface").ConfigureAwait(false);
56+
await this.TestTypeWithDocumentationAsync(type).ConfigureAwait(false);
8957
}
9058

9159
[Fact]

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1648UnitTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,10 +402,10 @@ public async Task TestIncorrectDelegateInheritDocAsync()
402402
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
403403
}
404404

405-
private static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult expected, CancellationToken cancellationToken)
405+
protected static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult expected, CancellationToken cancellationToken)
406406
=> VerifyCSharpDiagnosticAsync(source, new[] { expected }, cancellationToken);
407407

408-
private static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult[] expected, CancellationToken cancellationToken)
408+
protected static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult[] expected, CancellationToken cancellationToken)
409409
{
410410
var test = CreateTest(expected);
411411
test.TestCode = source;

StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1600ElementsMustBeDocumented.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace StyleCop.Analyzers.DocumentationRules
1313
using Microsoft.CodeAnalysis.CSharp.Syntax;
1414
using Microsoft.CodeAnalysis.Diagnostics;
1515
using StyleCop.Analyzers.Helpers;
16+
using StyleCop.Analyzers.Lightup;
1617
using StyleCop.Analyzers.Settings.ObjectModel;
1718

1819
/// <summary>
@@ -24,7 +25,7 @@ namespace StyleCop.Analyzers.DocumentationRules
2425
///
2526
/// <para>A violation of this rule occurs if an element is completely missing a documentation header, or if the
2627
/// header is empty. In C# the following types of elements can have documentation headers: classes, constructors,
27-
/// delegates, enums, events, finalizers, indexers, interfaces, methods, properties, and structs.</para>
28+
/// delegates, enums, events, finalizers, indexers, interfaces, methods, properties, records, and structs.</para>
2829
/// </remarks>
2930
[DiagnosticAnalyzer(LanguageNames.CSharp)]
3031
internal class SA1600ElementsMustBeDocumented : DiagnosticAnalyzer
@@ -41,9 +42,6 @@ internal class SA1600ElementsMustBeDocumented : DiagnosticAnalyzer
4142
private static readonly DiagnosticDescriptor Descriptor =
4243
new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.DocumentationRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink);
4344

44-
private static readonly ImmutableArray<SyntaxKind> BaseTypeDeclarationKinds =
45-
ImmutableArray.Create(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.InterfaceDeclaration, SyntaxKind.EnumDeclaration);
46-
4745
private static readonly Action<SyntaxNodeAnalysisContext, StyleCopSettings> BaseTypeDeclarationAction = Analyzer.HandleBaseTypeDeclaration;
4846
private static readonly Action<SyntaxNodeAnalysisContext, StyleCopSettings> MethodDeclarationAction = Analyzer.HandleMethodDeclaration;
4947
private static readonly Action<SyntaxNodeAnalysisContext, StyleCopSettings> ConstructorDeclarationAction = Analyzer.HandleConstructorDeclaration;
@@ -114,7 +112,7 @@ public override void Initialize(AnalysisContext context)
114112

115113
context.RegisterCompilationStartAction(context =>
116114
{
117-
context.RegisterSyntaxNodeAction(BaseTypeDeclarationAction, BaseTypeDeclarationKinds);
115+
context.RegisterSyntaxNodeAction(BaseTypeDeclarationAction, SyntaxKinds.BaseTypeDeclaration);
118116
context.RegisterSyntaxNodeAction(MethodDeclarationAction, SyntaxKind.MethodDeclaration);
119117
context.RegisterSyntaxNodeAction(ConstructorDeclarationAction, SyntaxKind.ConstructorDeclaration);
120118
context.RegisterSyntaxNodeAction(DestructorDeclarationAction, SyntaxKind.DestructorDeclaration);

StyleCop.Analyzers/StyleCop.Analyzers/Helpers/NamedTypeHelpers.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,6 @@ internal static bool IsPartialDeclaration(MemberDeclarationSyntax declaration)
145145
/// <returns>true if the member is implementing an interface member, otherwise false.</returns>
146146
internal static bool IsImplementingAnInterfaceMember(ISymbol memberSymbol)
147147
{
148-
if (memberSymbol.IsStatic)
149-
{
150-
return false;
151-
}
152-
153148
bool isImplementingExplicitly;
154149

155150
// Only methods, properties and events can implement an interface member

StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1119StatementMustNotUseUnnecessaryParenthesis.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,15 @@ private static void HandleParenthesizedExpression(SyntaxNodeAnalysisContext cont
153153
return;
154154
}
155155

156+
if (node.Parent is AssignmentExpressionSyntax assignmentExpression
157+
&& node.Expression.IsKind(SyntaxKind.ConditionalExpression)
158+
&& assignmentExpression.Left == node)
159+
{
160+
// NOTE: This is only valid syntax if the conditional expression is a ref expression
161+
// Parenthesis can't be removed here
162+
return;
163+
}
164+
156165
if (!(node.Parent is ExpressionSyntax)
157166
|| node.Parent is CheckedExpressionSyntax
158167
|| node.Parent is MemberAccessExpressionSyntax)
@@ -230,6 +239,7 @@ private static bool IsSwitchOrWithExpressionWithRequiredParentheses(Parenthesize
230239
MemberAccessExpressionSyntax memberAccessExpression => memberAccessExpression.Expression == outerExpression,
231240
ConditionalAccessExpressionSyntax conditionalAccessExpression => conditionalAccessExpression.Expression == outerExpression,
232241
ElementAccessExpressionSyntax elementAccessExpression => elementAccessExpression.Expression == outerExpression,
242+
InvocationExpressionSyntax invocationExpression => invocationExpression.Expression == outerExpression,
233243
_ => false,
234244
};
235245
}

documentation/SA1600.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ A C# code element is missing a documentation header.
2323

2424
C# syntax provides a mechanism for inserting documentation for classes and elements directly into the code, through the use of Xml documentation headers. For an introduction to these headers and a description of the header syntax, see the following article: [https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc/xml-documentation-comments](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc/xml-documentation-comments).
2525

26-
A violation of this rule occurs if an element is completely missing a documentation header, or if the header is empty. In C# the following types of elements can have documentation headers: classes, constructors, delegates, enums, events, finalizers, indexers, interfaces, methods, properties, and structs.
26+
A violation of this rule occurs if an element is completely missing a documentation header, or if the header is empty. In C# the following types of elements can have documentation headers: classes, constructors, delegates, enums, events, finalizers, indexers, interfaces, methods, properties, records, and structs.
2727

2828
## How to fix violations
2929

0 commit comments

Comments
 (0)