Skip to content

Commit 2f6e15a

Browse files
Merge pull request #6677 from dotnet/primaryConstructors
Do not fire 'make member static' when a method references a primary constructor parameter.
2 parents 2b6ab8d + 7b549bd commit 2f6e15a

File tree

2 files changed

+58
-18
lines changed

2 files changed

+58
-18
lines changed

src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/QualityGuidelines/MarkMembersAsStatic.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ void OnOperationBlockStart(OperationBlockStartAnalysisContext context)
104104

105105
context.RegisterOperationAction(context =>
106106
{
107-
if (((IInstanceReferenceOperation)context.Operation).ReferenceKind == InstanceReferenceKind.ContainingTypeInstance
107+
if (context.Operation is IInstanceReferenceOperation { ReferenceKind: InstanceReferenceKind.ContainingTypeInstance }
108108
&& (context.Operation.Parent is not IInvocationOperation invocation || !invocation.TargetMethod.Equals(methodSymbol, SymbolEqualityComparer.Default)))
109109
{
110110
isInstanceReferenced = true;
@@ -120,6 +120,17 @@ void OnOperationBlockStart(OperationBlockStartAnalysisContext context)
120120
}
121121
}, OperationKind.None);
122122

123+
context.RegisterOperationAction(context =>
124+
{
125+
if (context.Operation is IParameterReferenceOperation { Parameter.ContainingSymbol: IMethodSymbol { MethodKind: MethodKind.Constructor } })
126+
{
127+
// we're referencing a parameter not from our actual method, but from a type constructor.
128+
// This must be a primary constructor scenario, and we're capturing the parameter here.
129+
// This member cannot be made static.
130+
isInstanceReferenced = true;
131+
}
132+
}, OperationKind.ParameterReference);
133+
123134
context.RegisterOperationBlockEndAction(context =>
124135
{
125136
if (!isInstanceReferenced)

src/NetAnalyzers/UnitTests/Microsoft.CodeQuality.Analyzers/QualityGuidelines/MarkMembersAsStaticTests.cs

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
1+
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
22

33
using System;
44
using System.Threading.Tasks;
55
using Microsoft.CodeAnalysis.CSharp;
6+
using Microsoft.CodeQuality.CSharp.Analyzers.QualityGuidelines;
7+
using Microsoft.CodeQuality.VisualBasic.Analyzers.QualityGuidelines;
68
using Test.Utilities;
79
using Xunit;
8-
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
9-
Microsoft.CodeQuality.Analyzers.QualityGuidelines.MarkMembersAsStaticAnalyzer,
10-
Microsoft.CodeQuality.CSharp.Analyzers.QualityGuidelines.CSharpMarkMembersAsStaticFixer>;
11-
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
12-
Microsoft.CodeQuality.Analyzers.QualityGuidelines.MarkMembersAsStaticAnalyzer,
13-
Microsoft.CodeQuality.VisualBasic.Analyzers.QualityGuidelines.BasicMarkMembersAsStaticFixer>;
1410

1511
namespace Microsoft.CodeQuality.Analyzers.QualityGuidelines.UnitTests
1612
{
13+
using VerifyCS = CSharpCodeFixVerifier<MarkMembersAsStaticAnalyzer, CSharpMarkMembersAsStaticFixer>;
14+
using VerifyVB = VisualBasicCodeFixVerifier<MarkMembersAsStaticAnalyzer, BasicMarkMembersAsStaticFixer>;
15+
1716
public class MarkMembersAsStaticTests
1817
{
1918
[Fact]
@@ -1473,13 +1472,13 @@ public Task RecursiveMethod_DiagnosticAsync()
14731472
public class Test
14741473
{
14751474
public void [|Recursive|](string argument)
1476-
{
1477-
if (argument.Length > 1)
1478-
{
1475+
{
1476+
if (argument.Length > 1)
1477+
{
14791478
Recursive(argument[1..]);
1480-
}
1479+
}
14811480
1482-
Console.WriteLine($""argument[-1]: {argument}"");
1481+
Console.WriteLine($""argument[-1]: {argument}"");
14831482
}
14841483
}",
14851484
FixedCode = @"
@@ -1488,17 +1487,47 @@ public class Test
14881487
public class Test
14891488
{
14901489
public static void Recursive(string argument)
1491-
{
1492-
if (argument.Length > 1)
1493-
{
1490+
{
1491+
if (argument.Length > 1)
1492+
{
14941493
Recursive(argument[1..]);
1495-
}
1494+
}
14961495
1497-
Console.WriteLine($""argument[-1]: {argument}"");
1496+
Console.WriteLine($""argument[-1]: {argument}"");
14981497
}
14991498
}",
15001499
LanguageVersion = LanguageVersion.CSharp8
15011500
}.RunAsync();
15021501
}
1502+
1503+
[Fact(Skip = "Need update of roslyn to parse primary constructors properly"), WorkItem(6573, "https://github.com/dotnet/roslyn-analyzers/issues/6573")]
1504+
public Task PrimaryConstructor()
1505+
{
1506+
return new VerifyCS.Test
1507+
{
1508+
TestCode = """
1509+
using System;
1510+
using System.Collections.Generic;
1511+
using System.Linq;
1512+
1513+
public class Student(int id, string name, IEnumerable<decimal> grades)
1514+
{
1515+
public Student(int id, string name) : this(id, name, new List<decimal>()) { }
1516+
public int Id => id;
1517+
public string Name { get; set; } = name.Trim();
1518+
1519+
// validate property
1520+
public decimal GPA => grades.Any() ? grades.Average() : 4.0m;
1521+
1522+
// validate method
1523+
public decimal GetGPA() => grades.Any() ? grades.Average() : 4.0m;
1524+
1525+
// validate indexer
1526+
public int this[int x] => id;
1527+
}
1528+
""",
1529+
LanguageVersion = LanguageVersion.Preview
1530+
}.RunAsync();
1531+
}
15031532
}
15041533
}

0 commit comments

Comments
 (0)