Skip to content

Commit 20ccead

Browse files
authored
Merge pull request #4060 from sharwell/native-integers
Update for native integers in C# 9
2 parents 7033f3a + 1624b0a commit 20ccead

File tree

11 files changed

+325
-7
lines changed

11 files changed

+325
-7
lines changed

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1121CodeFixProvider.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,16 @@ private static SyntaxNode ComputeReplacement(SemanticModel semanticModel, Syntax
6666

6767
var type = semanticModel.GetSymbolInfo(node, cancellationToken).Symbol as INamedTypeSymbol;
6868

69-
PredefinedTypeSyntax typeSyntax;
70-
if (!SpecialTypeHelper.TryGetPredefinedType(type.SpecialType, out typeSyntax))
69+
TypeSyntax typeSyntax;
70+
if (SpecialTypeHelper.TryGetPredefinedType(type.SpecialType, out var predefinedType))
71+
{
72+
typeSyntax = predefinedType;
73+
}
74+
else if (type.SpecialType is SpecialType.System_IntPtr or SpecialType.System_UIntPtr)
75+
{
76+
typeSyntax = SyntaxFactory.IdentifierName(type.SpecialType == SpecialType.System_IntPtr ? "nint" : "nuint");
77+
}
78+
else
7179
{
7280
return node;
7381
}

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1129CodeFixProvider.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ private static SyntaxNode GetReplacementNode(Project project, SyntaxNode node, S
7171
var namedTypeSymbol = (symbolInfo.Symbol as IMethodSymbol)?.ContainingType;
7272

7373
var type = GetOrCreateTypeSyntax(project, newExpression, namedTypeSymbol);
74+
bool supportsNativeSizedIntegers = semanticModel.Compilation.SupportsNativeSizedIntegers();
75+
bool usesNativeSizedIntegerKeyword = IsNativeSizedIntegerKeyword(type);
7476

7577
SyntaxNode replacement;
7678

@@ -83,6 +85,12 @@ private static SyntaxNode GetReplacementNode(Project project, SyntaxNode node, S
8385
{
8486
replacement = SyntaxFactory.DefaultExpression(type);
8587
}
88+
else if (!supportsNativeSizedIntegers && usesNativeSizedIntegerKeyword)
89+
{
90+
// nint.Zero and nuint.Zero are only available in C# 11 with .NET 7+. For older versions, we need to
91+
// keep using 'default(nint)'.
92+
replacement = SyntaxFactory.DefaultExpression(type);
93+
}
8694
else
8795
{
8896
string fieldName;
@@ -121,6 +129,11 @@ private static SyntaxNode GetReplacementNode(Project project, SyntaxNode node, S
121129
.WithTrailingTrivia(newExpression.SyntaxNode.GetTrailingTrivia());
122130
}
123131

132+
private static bool IsNativeSizedIntegerKeyword(TypeSyntax type)
133+
{
134+
return type is IdentifierNameSyntax { Identifier.ValueText: "nint" or "nuint" };
135+
}
136+
124137
private static TypeSyntax GetOrCreateTypeSyntax(Project project, BaseObjectCreationExpressionSyntaxWrapper baseObjectCreationExpression, INamedTypeSymbol constructedType)
125138
{
126139
if (baseObjectCreationExpression.SyntaxNode is ObjectCreationExpressionSyntax objectCreationExpressionSyntax)

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/ReadabilityRules/SA1121CSharp11UnitTests.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace StyleCop.Analyzers.Test.CSharp11.ReadabilityRules
55
{
66
using System.Threading;
77
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
89
using StyleCop.Analyzers.Test.CSharp10.ReadabilityRules;
910
using Xunit;
1011

@@ -64,5 +65,54 @@ class TestClass
6465
FixedSources = { newSource },
6566
}.RunAsync(CancellationToken.None).ConfigureAwait(false);
6667
}
68+
69+
[Fact]
70+
[WorkItem(3969, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3969")]
71+
public async Task TestNativeSizedIntegersReportWithNet70Async()
72+
{
73+
var testCode = @"
74+
using System;
75+
76+
class TestClass
77+
{
78+
[|IntPtr|] field1;
79+
[|System.UIntPtr|] field2;
80+
}";
81+
82+
var fixedCode = @"
83+
using System;
84+
85+
class TestClass
86+
{
87+
nint field1;
88+
nuint field2;
89+
}";
90+
91+
await new CSharpTest
92+
{
93+
TestCode = testCode,
94+
FixedCode = fixedCode,
95+
}.RunAsync(CancellationToken.None).ConfigureAwait(false);
96+
}
97+
98+
[Fact]
99+
[WorkItem(3969, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3969")]
100+
public async Task TestNativeSizedIntegersDoNotReportWithNet60Async()
101+
{
102+
var testCode = @"
103+
using System;
104+
105+
class TestClass
106+
{
107+
IntPtr field1;
108+
System.UIntPtr field2;
109+
}";
110+
111+
await new CSharpTest
112+
{
113+
ReferenceAssemblies = ReferenceAssemblies.Net.Net60,
114+
TestCode = testCode,
115+
}.RunAsync(CancellationToken.None).ConfigureAwait(false);
116+
}
67117
}
68118
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/ReadabilityRules/SA1129CSharp11UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp11.ReadabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp10.ReadabilityRules;
10+
using Xunit;
11+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
12+
StyleCop.Analyzers.ReadabilityRules.SA1129DoNotUseDefaultValueTypeConstructor,
13+
StyleCop.Analyzers.ReadabilityRules.SA1129CodeFixProvider>;
714

815
public partial class SA1129CSharp11UnitTests : SA1129CSharp10UnitTests
916
{
17+
[Fact]
18+
[WorkItem(3969, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3969")]
19+
public async Task VerifyNativeSizedIntegerCreationWithNet70Async()
20+
{
21+
var testCode = @"
22+
using System;
23+
24+
class TestClass
25+
{
26+
void TestMethod()
27+
{
28+
nint nativeInt = [|new nint()|];
29+
nuint nativeUInt = [|new nuint()|];
30+
}
31+
}";
32+
33+
var fixedCode = @"
34+
using System;
35+
36+
class TestClass
37+
{
38+
void TestMethod()
39+
{
40+
nint nativeInt = nint.Zero;
41+
nuint nativeUInt = nuint.Zero;
42+
}
43+
}";
44+
45+
await VerifyCSharpFixAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, fixedCode, CancellationToken.None).ConfigureAwait(false);
46+
}
47+
48+
[Fact]
49+
[WorkItem(3969, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3969")]
50+
public async Task VerifyNativeSizedIntegerCreationWithNet60Async()
51+
{
52+
var testCode = @"
53+
using System;
54+
55+
class TestClass
56+
{
57+
void TestMethod()
58+
{
59+
nint nativeInt = [|new nint()|];
60+
nuint nativeUInt = [|new nuint()|];
61+
}
62+
}";
63+
64+
var fixedCode = @"
65+
using System;
66+
67+
class TestClass
68+
{
69+
void TestMethod()
70+
{
71+
nint nativeInt = default(nint);
72+
nuint nativeUInt = default(nuint);
73+
}
74+
}";
75+
76+
await new CSharpTest
77+
{
78+
ReferenceAssemblies = ReferenceAssemblies.Net.Net60,
79+
TestCode = testCode,
80+
FixedCode = fixedCode,
81+
}.RunAsync(CancellationToken.None).ConfigureAwait(false);
82+
}
1083
}
1184
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/ReadabilityRules/SA1121CSharp9UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp9.ReadabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
9+
using StyleCop.Analyzers.Lightup;
610
using StyleCop.Analyzers.Test.CSharp8.ReadabilityRules;
11+
using Xunit;
12+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
13+
StyleCop.Analyzers.ReadabilityRules.SA1121UseBuiltInTypeAlias,
14+
StyleCop.Analyzers.ReadabilityRules.SA1121CodeFixProvider>;
715

816
public partial class SA1121CSharp9UnitTests : SA1121CSharp8UnitTests
917
{
18+
[Fact]
19+
[WorkItem(3969, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3969")]
20+
public async Task TestNativeSizedIntegersDoNotReportAsync()
21+
{
22+
// Explicitly test with C# 9 since C# 11 and later include separate coverage where these cases do report.
23+
var testCode = @"
24+
using System;
25+
26+
class TestClass
27+
{
28+
IntPtr field1;
29+
System.UIntPtr field2;
30+
}";
31+
32+
await VerifyCSharpDiagnosticAsync(LanguageVersionEx.CSharp9, testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
33+
}
34+
35+
[Fact]
36+
[WorkItem(3969, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3969")]
37+
public async Task TestNativeSizedIntegerAliasesDoNotReportAsync()
38+
{
39+
var testCode = @"
40+
class TestClass
41+
{
42+
nint field1;
43+
nuint field2;
44+
}";
45+
46+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
47+
}
1048
}
1149
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/ReadabilityRules/SA1125CSharp9UnitTests.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.CSharp9.ReadabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp8.ReadabilityRules;
10+
using Xunit;
11+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopDiagnosticVerifier<StyleCop.Analyzers.ReadabilityRules.SA1125UseShorthandForNullableTypes>;
712

813
public partial class SA1125CSharp9UnitTests : SA1125CSharp8UnitTests
914
{
15+
[Theory]
16+
[InlineData("System.Nullable<nint>")]
17+
[InlineData("Nullable<IntPtr>")]
18+
[InlineData("System.Nullable<nuint>")]
19+
[InlineData("Nullable<UIntPtr>")]
20+
[WorkItem(3969, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3969")]
21+
public async Task TestNativeSizedNullableTypesAsync(string nullableForm)
22+
{
23+
var testCode = @"
24+
using System;
25+
26+
class TestClass
27+
{
28+
{|#0:" + nullableForm + @"|} value;
29+
}";
30+
31+
await VerifyCSharpDiagnosticAsync(testCode, Diagnostic().WithLocation(0), CancellationToken.None).ConfigureAwait(false);
32+
}
33+
34+
[Fact]
35+
[WorkItem(3969, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3969")]
36+
public async Task TestNativeSizedNullableAliasesDoNotReportAsync()
37+
{
38+
var testCode = @"
39+
class TestClass
40+
{
41+
nint? nativeInt;
42+
nuint? nativeUInt;
43+
}";
44+
45+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
46+
}
1047
}
1148
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/ReadabilityRules/SA1129CSharp9UnitTests.cs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
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.ReadabilityRules
75
{
86
using System.Threading;
97
using System.Threading.Tasks;
108
using Microsoft.CodeAnalysis.Testing;
9+
using StyleCop.Analyzers.Lightup;
1110
using StyleCop.Analyzers.Test.CSharp8.ReadabilityRules;
1211
using Xunit;
1312
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
@@ -46,5 +45,68 @@ internal static S F()
4645

4746
await VerifyCSharpFixAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, fixedTestCode, CancellationToken.None).ConfigureAwait(false);
4847
}
48+
49+
[Fact]
50+
[WorkItem(3969, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3969")]
51+
public async Task VerifyNativeSizedIntegerCreationAsync()
52+
{
53+
var testCode = @"
54+
using System;
55+
56+
class TestClass
57+
{
58+
void TestMethod()
59+
{
60+
nint nativeInt = [|new nint()|];
61+
nuint nativeUInt = [|new nuint()|];
62+
}
63+
}";
64+
65+
var fixedTestCode = @"
66+
using System;
67+
68+
class TestClass
69+
{
70+
void TestMethod()
71+
{
72+
nint nativeInt = default(nint);
73+
nuint nativeUInt = default(nuint);
74+
}
75+
}";
76+
77+
// Force C# 9 language version even in later test scenarios
78+
await new CSharpTest(LanguageVersionEx.CSharp9)
79+
{
80+
TestCode = testCode,
81+
FixedCode = fixedTestCode,
82+
}.RunAsync(CancellationToken.None).ConfigureAwait(false);
83+
}
84+
85+
[Fact]
86+
[WorkItem(3969, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3969")]
87+
public async Task VerifyNativeSizedIntegerDefaultParameterValuesAsync()
88+
{
89+
var testCode = @"
90+
using System;
91+
92+
class TestClass
93+
{
94+
void TestMethod(nint nativeInt = [|new nint()|], nuint nativeUInt = [|new nuint()|])
95+
{
96+
}
97+
}";
98+
99+
var fixedTestCode = @"
100+
using System;
101+
102+
class TestClass
103+
{
104+
void TestMethod(nint nativeInt = default(nint), nuint nativeUInt = default(nuint))
105+
{
106+
}
107+
}";
108+
109+
await VerifyCSharpFixAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, fixedTestCode, CancellationToken.None).ConfigureAwait(false);
110+
}
49111
}
50112
}

0 commit comments

Comments
 (0)