Skip to content

Commit 8ca93fe

Browse files
committed
Update SA1000 for function pointers
1 parent 3afc18b commit 8ca93fe

File tree

4 files changed

+50
-2
lines changed

4 files changed

+50
-2
lines changed

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/SpacingRules/SA1000CSharp9UnitTests.cs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
22
// Licensed under the MIT License. See LICENSE in the project root for license information.
33

4-
#nullable disable
5-
64
namespace StyleCop.Analyzers.Test.CSharp9.SpacingRules
75
{
6+
using System.Threading;
87
using System.Threading.Tasks;
98
using Microsoft.CodeAnalysis.Testing;
109
using StyleCop.Analyzers.Test.CSharp8.SpacingRules;
@@ -16,6 +15,33 @@ namespace StyleCop.Analyzers.Test.CSharp9.SpacingRules
1615

1716
public partial class SA1000CSharp9UnitTests : SA1000CSharp8UnitTests
1817
{
18+
[Fact]
19+
[WorkItem(3970, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3970")]
20+
public async Task TestFunctionPointerKeywordSpacingAsync()
21+
{
22+
var testCode = @"public class TestClass
23+
{
24+
private unsafe {|#0:delegate|} *<int, void> pointer1;
25+
private unsafe delegate* {|#1:unmanaged|} [Cdecl]<int, void> pointer2;
26+
}
27+
";
28+
29+
var fixedCode = @"public class TestClass
30+
{
31+
private unsafe delegate*<int, void> pointer1;
32+
private unsafe delegate* unmanaged[Cdecl]<int, void> pointer2;
33+
}
34+
";
35+
36+
var expected = new[]
37+
{
38+
Diagnostic().WithArguments("delegate", " not").WithLocation(0),
39+
Diagnostic().WithArguments("unmanaged", " not").WithLocation(1),
40+
};
41+
42+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
43+
}
44+
1945
[Fact]
2046
public async Task TestTargetTypedNewAsync()
2147
{

StyleCop.Analyzers/StyleCop.Analyzers/Lightup/SyntaxKindEx.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ internal static class SyntaxKindEx
7171
public const SyntaxKind FunctionPointerType = (SyntaxKind)9056;
7272
public const SyntaxKind FunctionPointerParameter = (SyntaxKind)9057;
7373
public const SyntaxKind FunctionPointerParameterList = (SyntaxKind)9058;
74+
public const SyntaxKind FunctionPointerCallingConvention = (SyntaxKind)9059;
7475
public const SyntaxKind InitAccessorDeclaration = (SyntaxKind)9060;
7576
public const SyntaxKind WithExpression = (SyntaxKind)9061;
7677
public const SyntaxKind WithInitializerExpression = (SyntaxKind)9062;

StyleCop.Analyzers/StyleCop.Analyzers/SpacingRules/SA1000KeywordsMustBeSpacedCorrectly.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
8585
{
8686
switch (token.Kind())
8787
{
88+
case SyntaxKind.DelegateKeyword:
89+
if (token.Parent.IsKind(SyntaxKindEx.FunctionPointerType))
90+
{
91+
HandleDisallowedSpaceToken(ref context, token);
92+
break;
93+
}
94+
95+
goto default;
96+
8897
case SyntaxKindEx.AndKeyword:
8998
case SyntaxKind.AwaitKeyword:
9099
case SyntaxKind.CaseKeyword:
@@ -167,6 +176,14 @@ private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
167176
HandleThrowKeywordToken(ref context, token);
168177
break;
169178

179+
case SyntaxKindEx.UnmanagedKeyword:
180+
if (token.Parent.IsKind(SyntaxKindEx.FunctionPointerCallingConvention))
181+
{
182+
HandleDisallowedSpaceToken(ref context, token);
183+
}
184+
185+
break;
186+
170187
default:
171188
break;
172189
}

documentation/SA1000.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ The `new` and `stackalloc` keywords should always be followed by a space, except
4242
The `throw` keyword should always be followed by a space, unless it is part of a re-throw statement, in which case there
4343
should be no space between the `throw` keyword and the semicolon.
4444

45+
In C# 9 function pointer syntax, the `delegate` keyword must not be followed by a space before the `*`, and the
46+
`unmanaged` keyword must not be followed by a space before the optional calling convention list. For example,
47+
`delegate*<int, void>` and `delegate* unmanaged[Cdecl]<int, void>` show the expected spacing for this feature.
48+
4549
## How to fix violations
4650

4751
To fix a violation of this rule, add or remove a space after the keyword, according to the description above.

0 commit comments

Comments
 (0)