|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeFixes.NamingStyles;
using Microsoft.CodeAnalysis.CSharp.Diagnostics.NamingStyles;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics.NamingStyles;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.NamingStyles;
[Trait(Traits.Feature, Traits.Features.NamingStyle)]
public sealed class NamingStylesTests(ITestOutputHelper logger)
: AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor(logger)
{
private static readonly NamingStylesTestOptionSets s_options = new(LanguageNames.CSharp);
internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
=> (new CSharpNamingStyleDiagnosticAnalyzer(), new NamingStyleCodeFixProvider());
protected override TestComposition GetComposition()
=> base.GetComposition().AddParts(typeof(TestSymbolRenamedCodeActionOperationFactoryWorkspaceService));
[Fact]
public async Task TestPascalCaseClass_CorrectName()
{
await TestMissingInRegularAndScriptAsync(
"""
class [|C|]
{
}
""", new TestParameters(options: s_options.ClassNamesArePascalCase));
}
[Fact]
public async Task TestPascalCaseClass_NameGetsCapitalized()
{
await TestInRegularAndScriptAsync(
"""
class [|c|]
{
}
""",
"""
class C
{
}
""",
options: s_options.ClassNamesArePascalCase);
}
[Theory]
[InlineData("M_bar", "bar")]
[InlineData("S_bar", "bar")]
[InlineData("T_bar", "bar")]
[InlineData("_Bar", "bar")]
[InlineData("__Bar", "bar")]
[InlineData("M_s__t_Bar", "bar")]
[InlineData("m_bar", "bar")]
[InlineData("s_bar", "bar")]
[InlineData("t_bar", "bar")]
[InlineData("_bar", "bar")]
[InlineData("__bar", "bar")]
[InlineData("m_s__t_Bar", "bar")]
// Special cases to ensure empty identifiers are not produced
[InlineData("M_", "m_")]
[InlineData("M__", "_")]
[InlineData("S_", "s_")]
[InlineData("T_", "t_")]
[InlineData("M_S__T_", "t_")]
public async Task TestCamelCaseField_PrefixGetsStripped(string fieldName, string correctedName)
{
await TestInRegularAndScriptAsync(
$$"""
class C
{
int [|{{fieldName}}|];
}
""",
$$"""
class C
{
int [|{{correctedName}}|];
}
""",
options: s_options.FieldNamesAreCamelCase);
}
[Theory]
[InlineData("M_bar", "_bar")]
[InlineData("S_bar", "_bar")]
[InlineData("T_bar", "_bar")]
[InlineData("_Bar", "_bar")]
[InlineData("__Bar", "_bar")]
[InlineData("M_s__t_Bar", "_bar")]
[InlineData("m_bar", "_bar")]
[InlineData("s_bar", "_bar")]
[InlineData("t_bar", "_bar")]
[InlineData("bar", "_bar")]
[InlineData("__bar", "_bar")]
[InlineData("__s_bar", "_bar")]
[InlineData("m_s__t_Bar", "_bar")]
// Special cases to ensure empty identifiers are not produced
[InlineData("M_", "_m_")]
[InlineData("M__", "_")]
[InlineData("S_", "_s_")]
[InlineData("T_", "_t_")]
[InlineData("M_S__T_", "_t_")]
public async Task TestCamelCaseField_PrefixGetsStrippedBeforeAddition(string fieldName, string correctedName)
{
await TestInRegularAndScriptAsync(
$$"""
class C
{
int [|{{fieldName}}|];
}
""",
$$"""
class C
{
int [|{{correctedName}}|];
}
""",
options: s_options.FieldNamesAreCamelCaseWithUnderscorePrefix);
}
[Fact]
public async Task TestPascalCaseMethod_CorrectName()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void [|M|]()
{
}
}
""", new TestParameters(options: s_options.MethodNamesArePascalCase));
}
[Theory]
[InlineData("")]
[InlineData("public")]
[InlineData("protected")]
[InlineData("internal")]
[InlineData("protected internal")]
[InlineData("private")]
[InlineData("protected private")]
[WorkItem("https://github.com/dotnet/roslyn/issues/20907")]
public async Task TestPascalCaseMethod_NoneAndDefaultAccessibilities(string accessibility)
{
await TestMissingInRegularAndScriptAsync(
$$"""
class C
{
{{accessibility}} void [|m|]()
{
}
}
""", new TestParameters(options: s_options.MethodNamesWithAccessibilityArePascalCase([])));
await TestInRegularAndScriptAsync(
$$"""
class C
{
{{accessibility}} void [|m|]()
{
}
}
""",
$$"""
class C
{
{{accessibility}} void M()
{
}
}
""", options: s_options.MethodNamesWithAccessibilityArePascalCase(accessibilities: default));
}
[Theory]
[InlineData("} namespace [|c2|] {", "} namespace C2 {")]
[InlineData("class [|c2|] { }", "class C2 { }")]
[InlineData("struct [|c2|] { }", "struct C2 { }")]
[InlineData("interface [|c2|] { }", "interface C2 { }")]
[InlineData("delegate void [|c2|]();", "delegate void C2();")]
[InlineData("enum [|c2|] { }", "enum C2 { }")]
[InlineData("class M<[|t|]> {}", "class M<T> {}")]
[InlineData("void M<[|t|]>() {}", "void M<T>() {}")]
[InlineData("int [|m|] { get; }", "int M { get; }")]
[InlineData("void [|m|]() {}", "void M() {}")]
[InlineData("void Outer() { void [|m|]() {} }", "void Outer() { void M() {} }")]
[InlineData("int [|m|];", "int M;")]
[InlineData("event System.EventHandler [|m|];", "event System.EventHandler M;")]
[InlineData("void Outer(int [|m|]) {}", "void Outer(int M) {}")]
[InlineData("void Outer() { int [|m|]; }", "void Outer() { int M; }")]
[WorkItem("https://github.com/dotnet/roslyn/issues/20907")]
public async Task TestPascalCaseSymbol_NoneAndDefaultSymbolKinds(string camelCaseSymbol, string pascalCaseSymbol)
{
await TestMissingInRegularAndScriptAsync(
$$"""
class C
{
{{camelCaseSymbol}}
}
""", new TestParameters(options: s_options.SymbolKindsArePascalCaseEmpty()));
await TestInRegularAndScriptAsync(
$$"""
class C
{
{{camelCaseSymbol}}
}
""",
$$"""
class C
{
{{pascalCaseSymbol}}
}
""", options: s_options.SymbolKindsArePascalCase(symbolKinds: default));
}
[Theory]
[InlineData("} namespace [|c2|] {", "} namespace C2 {", SymbolKind.Namespace, Accessibility.Public)]
[InlineData("class [|c2|] { }", "class C2 { }", TypeKind.Class, Accessibility.Private)]
[InlineData("struct [|c2|] { }", "struct C2 { }", TypeKind.Struct, Accessibility.Private)]
[InlineData("interface [|c2|] { }", "interface C2 { }", TypeKind.Interface, Accessibility.Private)]
[InlineData("delegate void [|c2|]();", "delegate void C2();", TypeKind.Delegate, Accessibility.Private)]
[InlineData("enum [|c2|] { }", "enum C2 { }", TypeKind.Enum, Accessibility.Private)]
[InlineData("class M<[|t|]> {}", "class M<T> {}", SymbolKind.TypeParameter, Accessibility.Private)]
[InlineData("void M<[|t|]>() {}", "void M<T>() {}", SymbolKind.TypeParameter, Accessibility.Private)]
[InlineData("int [|m|] { get; }", "int M { get; }", SymbolKind.Property, Accessibility.Private)]
[InlineData("void [|m|]() {}", "void M() {}", MethodKind.Ordinary, Accessibility.Private)]
[InlineData("void Outer() { void [|m|]() {} }", "void Outer() { void M() {} }", MethodKind.LocalFunction, Accessibility.NotApplicable)]
[InlineData("int [|m|];", "int M;", SymbolKind.Field, Accessibility.Private)]
[InlineData("event System.EventHandler [|m|];", "event System.EventHandler M;", SymbolKind.Event, Accessibility.Private)]
[InlineData("void Outer(int [|m|]) {}", "void Outer(int M) {}", SymbolKind.Parameter, Accessibility.Private)]
[InlineData("void Outer() { void Inner(int [|m|]) {} }", "void Outer() { void Inner(int M) {} }", SymbolKind.Parameter, Accessibility.NotApplicable)]
[InlineData("void Outer() { System.Action<int> action = [|m|] => {} }", "void Outer() { System.Action<int> action = M => {} }", SymbolKind.Parameter, Accessibility.NotApplicable)]
[InlineData("void Outer() { System.Action<int> action = ([|m|]) => {} }", "void Outer() { System.Action<int> action = (M) => {} }", SymbolKind.Parameter, Accessibility.NotApplicable)]
[InlineData("void Outer() { System.Action<int> action = (int [|m|]) => {} }", "void Outer() { System.Action<int> action = (int M) => {} }", SymbolKind.Parameter, Accessibility.NotApplicable)]
[InlineData("void Outer() { System.Action<int> action = delegate (int [|m|]) {} }", "void Outer() { System.Action<int> action = delegate (int M) {} }", SymbolKind.Parameter, Accessibility.NotApplicable)]
[InlineData("void Outer() { int [|m|]; }", "void Outer() { int M; }", SymbolKind.Local, Accessibility.NotApplicable)]
[WorkItem("https://github.com/dotnet/roslyn/issues/20907")]
public async Task TestPascalCaseSymbol_ExpectedSymbolAndAccessibility(string camelCaseSymbol, string pascalCaseSymbol, object symbolKind, Accessibility accessibility)
{
var alternateSymbolKind = TypeKind.Class.Equals(symbolKind) ? TypeKind.Interface : TypeKind.Class;
var alternateAccessibility = accessibility == Accessibility.Public ? Accessibility.Protected : Accessibility.Public;
// Verify that no diagnostic is reported if the symbol kind is wrong
await TestMissingInRegularAndScriptAsync(
$$"""
class C
{
{{camelCaseSymbol}}
}
""", new TestParameters(options: s_options.SymbolKindsArePascalCase(alternateSymbolKind)));
// Verify that no diagnostic is reported if the accessibility is wrong
await TestMissingInRegularAndScriptAsync(
$$"""
class C
{
{{camelCaseSymbol}}
}
""", new TestParameters(options: s_options.AccessibilitiesArePascalCase(ImmutableArray.Create(alternateAccessibility))));
await TestInRegularAndScriptAsync(
$$"""
class C
{
{{camelCaseSymbol}}
}
""",
$$"""
class C
{
{{pascalCaseSymbol}}
}
""", options: s_options.AccessibilitiesArePascalCase(ImmutableArray.Create(accessibility)));
}
[Fact]
public async Task TestPascalCaseMethod_NameGetsCapitalized()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void [|m|]()
{
}
}
""",
"""
class C
{
void M()
{
}
}
""",
options: s_options.MethodNamesArePascalCase);
}
[Fact]
public async Task TestPascalCaseMethod_ConstructorsAreIgnored()
{
await TestMissingInRegularAndScriptAsync(
"""
class c
{
public [|c|]()
{
}
}
""", new TestParameters(options: s_options.MethodNamesArePascalCase));
}
[Fact]
public async Task TestPascalCaseMethod_PropertyAccessorsAreIgnored()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
public int P { [|get|]; set; }
}
""", new TestParameters(options: s_options.MethodNamesArePascalCase));
}
[Fact]
public async Task TestPascalCaseMethod_IndexerNameIsIgnored()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
public int [|this|][int index]
{
get
{
return 1;
}
}
}
""", new TestParameters(options: s_options.MethodNamesArePascalCase));
}
[Fact]
public async Task TestPascalCaseMethod_LocalFunctionIsIgnored()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M()
{
void [|f|]()
{
}
}
}
""", new TestParameters(options: s_options.MethodNamesArePascalCase));
}
[Fact]
public async Task TestCamelCaseParameters()
{
await TestInRegularAndScriptAsync(
"""
class C
{
public void M(int [|X|])
{
}
}
""",
"""
class C
{
public void M(int x)
{
}
}
""",
options: s_options.ParameterNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_LocalDeclaration1()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
int [|X|];
}
}
""",
"""
class C
{
void M()
{
int x;
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_LocalDeclaration2()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
int X, [|Y|] = 0;
}
}
""",
"""
class C
{
void M()
{
int X, y = 0;
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_UsingVariable1()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
using (object [|A|] = null)
{
}
}
}
""",
"""
class C
{
void M()
{
using (object a = null)
{
}
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_UsingVariable2()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
using (object A = null, [|B|] = null)
{
}
}
}
""",
"""
class C
{
void M()
{
using (object A = null, b = null)
{
}
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_ForVariable1()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
for (int [|I|] = 0, J = 0; I < J; ++I)
{
}
}
}
""",
"""
class C
{
void M()
{
for (int i = 0, J = 0; i < J; ++i)
{
}
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_ForVariable2()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
for (int I = 0, [|J|] = 0; I < J; ++J)
{
}
}
}
""",
"""
class C
{
void M()
{
for (int I = 0, j = 0; I < j; ++j)
{
}
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_ForEachVariable()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
foreach (var [|X|] in new string[] { })
{
}
}
}
""",
"""
class C
{
void M()
{
foreach (var x in new string[] { })
{
}
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_CatchVariable()
{
await TestInRegularAndScriptAsync(
"""
using System;
class C
{
void M()
{
try
{
}
catch (Exception [|Exception|])
{
}
}
}
""",
"""
using System;
class C
{
void M()
{
try
{
}
catch (Exception exception)
{
}
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_CatchWithoutVariableIgnored()
{
await TestMissingInRegularAndScriptAsync(
"""
using System;
class C
{
void M()
{
try
{
}
catch ([|Exception|])
{
}
}
}
""", new TestParameters(options: s_options.LocalNamesAreCamelCase));
}
[Fact]
public async Task TestCamelCaseLocals_CatchWithoutDeclarationIgnored()
{
await TestMissingInRegularAndScriptAsync(
"""
using System;
class C
{
void M()
{
try
{
}
[|catch|]
{
}
}
}
""", new TestParameters(options: s_options.LocalNamesAreCamelCase));
}
[Fact]
public async Task TestCamelCaseLocals_Deconstruction1()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
(int A, (string [|B|], var C)) = (0, (string.Empty, string.Empty));
System.Console.WriteLine(A + B + C);
}
}
""",
"""
class C
{
void M()
{
(int A, (string b, var C)) = (0, (string.Empty, string.Empty));
System.Console.WriteLine(A + b + C);
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_Deconstruction2()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
var (A, (B, [|C|])) = (0, (string.Empty, string.Empty));
System.Console.WriteLine(A + B + C);
}
}
""",
"""
class C
{
void M()
{
var (A, (B, [|c|])) = (0, (string.Empty, string.Empty));
System.Console.WriteLine(A + B + c);
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_ForEachDeconstruction1()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
foreach ((int A, (string [|B|], var C)) in new[] { (0, (string.Empty, string.Empty)) })
System.Console.WriteLine(A + B + C);
}
}
""",
"""
class C
{
void M()
{
foreach ((int A, (string b, var C)) in new[] { (0, (string.Empty, string.Empty)) })
System.Console.WriteLine(A + b + C);
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_ForEachDeconstruction2()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
foreach (var (A, (B, [|C|])) in new[] { (0, (string.Empty, string.Empty)) })
System.Console.WriteLine(A + B + C);
}
}
""",
"""
class C
{
void M()
{
foreach (var (A, (B, c)) in new[] { (0, (string.Empty, string.Empty)) })
System.Console.WriteLine(A + B + c);
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_OutVariable()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
if (int.TryParse(string.Empty, out var [|Value|]))
System.Console.WriteLine(Value);
}
}
""",
"""
class C
{
void M()
{
if (int.TryParse(string.Empty, out var value))
System.Console.WriteLine(value);
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_PatternVariable()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
if (new object() is int [|Value|])
System.Console.WriteLine(Value);
}
}
""",
"""
class C
{
void M()
{
if (new object() is int value)
System.Console.WriteLine(value);
}
}
""",
options: s_options.LocalNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocals_QueryFromClauseIgnored()
{
// This is an IRangeVariableSymbol, not ILocalSymbol
await TestMissingInRegularAndScriptAsync(
"""
using System.Linq;
class C
{
void M()
{
var squares =
from [|STRING|] in new string[] { }
let Number = int.Parse(STRING)
select Number * Number;
}
}
""", new TestParameters(options: s_options.LocalNamesAreCamelCase));
}
[Fact]
public async Task TestCamelCaseLocals_QueryLetClauseIgnored()
{
// This is an IRangeVariableSymbol, not ILocalSymbol
await TestMissingInRegularAndScriptAsync(
"""
using System.Linq;
class C
{
void M()
{
var squares =
from STRING in new string[] { }
let [|Number|] = int.Parse(STRING)
select Number * Number;
}
}
""", new TestParameters(options: s_options.LocalNamesAreCamelCase));
}
[Fact]
public async Task TestCamelCaseLocals_ParameterIgnored()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(int [|X|])
{
}
}
""", new TestParameters(options: s_options.LocalNamesAreCamelCase));
}
[Fact]
public async Task TestCamelCaseLocals_TupleTypeElementNameIgnored1()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M()
{
(int [|A|], string B) tuple;
}
}
""", new TestParameters(options: s_options.LocalNamesAreCamelCase));
}
[Fact]
public async Task TestCamelCaseLocals_TupleTypeElementNameIgnored2()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M()
{
(int A, (string [|B|], string C)) tuple = (0, (string.Empty, string.Empty));
}
}
""", new TestParameters(options: s_options.LocalNamesAreCamelCase));
}
[Fact]
public async Task TestCamelCaseLocals_TupleExpressionElementNameIgnored()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M()
{
var tuple = ([|A|]: 0, B: 0);
}
}
""", new TestParameters(options: s_options.LocalNamesAreCamelCase));
}
[Fact]
public async Task TestUpperCaseConstants_ConstField()
{
await TestInRegularAndScriptAsync(
"""
class C
{
const int [|field|] = 0;
}
""",
"""
class C
{
const int FIELD = 0;
}
""",
options: s_options.ConstantsAreUpperCase);
}
[Fact]
public async Task TestUpperCaseConstants_ConstLocal()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
const int local1 = 0, [|local2|] = 0;
}
}
""",
"""
class C
{
void M()
{
const int local1 = 0, LOCAL2 = 0;
}
}
""",
options: s_options.ConstantsAreUpperCase);
}
[Fact]
public async Task TestUpperCaseConstants_NonConstFieldIgnored()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
readonly int [|field|] = 0;
}
""", new TestParameters(options: s_options.ConstantsAreUpperCase));
}
[Fact]
public async Task TestUpperCaseConstants_NonConstLocalIgnored()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M()
{
int local1 = 0, [|local2|] = 0;
}
}
""", new TestParameters(options: s_options.ConstantsAreUpperCase));
}
[Fact]
public async Task TestCamelCaseLocalsUpperCaseConstants_ConstLocal()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
const int [|PascalCase|] = 0;
}
}
""",
"""
class C
{
void M()
{
const int PASCALCASE = 0;
}
}
""",
options: s_options.LocalsAreCamelCaseConstantsAreUpperCase);
}
[Fact]
public async Task TestCamelCaseLocalsUpperCaseConstants_NonConstLocal()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
int [|PascalCase|] = 0;
}
}
""",
"""
class C
{
void M()
{
int pascalCase = 0;
}
}
""",
options: s_options.LocalsAreCamelCaseConstantsAreUpperCase);
}
[Fact]
public async Task TestCamelCaseLocalFunctions()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
void [|F|]()
{
}
}
}
""",
"""
class C
{
void M()
{
void f()
{
}
}
}
""",
options: s_options.LocalFunctionNamesAreCamelCase);
}
[Fact]
public async Task TestCamelCaseLocalFunctions_MethodIsIgnored()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void [|M|]()
{
}
}
""", new TestParameters(options: s_options.LocalFunctionNamesAreCamelCase));
}
[Fact]
public async Task TestAsyncFunctions_AsyncMethod()
{
await TestInRegularAndScriptAsync(
"""
class C
{
async void [|M|]()
{
}
}
""",
"""
class C
{
async void MAsync()
{
}
}
""",
options: s_options.AsyncFunctionNamesEndWithAsync);
}
[Fact]
public async Task TestAsyncFunctions_AsyncLocalFunction()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M()
{
async void [|F|]()
{
}
}
}
""",
"""
class C
{
void M()
{
async void FAsync()
{
}
}
}
""",
options: s_options.AsyncFunctionNamesEndWithAsync);
}
[Fact]
public async Task TestAsyncFunctions_NonAsyncMethodIgnored()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void [|M|]()
{
async void F()
{
}
}
}
""", new TestParameters(options: s_options.AsyncFunctionNamesEndWithAsync));
}
[Fact]
public async Task TestAsyncFunctions_NonAsyncLocalFunctionIgnored()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
async void M()
{
void [|F|]()
{
}
}
}
""", new TestParameters(options: s_options.AsyncFunctionNamesEndWithAsync));
}
[Fact]
public async Task TestPascalCaseMethod_InInterfaceWithImplicitImplementation()
{
await TestInRegularAndScriptAsync(
"""
interface I
{
void [|m|]();
}
class C : I
{
public void m() { }
}
""",
"""
interface I
{
void M();
}
class C : I
{
public void M() { }
}
""",
options: s_options.MethodNamesArePascalCase);
}
[Fact]
public async Task TestPascalCaseMethod_InInterfaceWithExplicitImplementation()
{
await TestInRegularAndScriptAsync(
"""
interface I
{
void [|m|]();
}
class C : I
{
void I.m() { }
}
""",
"""
interface I
{
void M();
}
class C : I
{
void I.M() { }
}
""",
options: s_options.MethodNamesArePascalCase);
}
[Fact]
public async Task TestPascalCaseMethod_NotInImplicitInterfaceImplementation()
{
await TestMissingInRegularAndScriptAsync(
"""
interface I
{
void m();
}
class C : I
{
public void [|m|]() { }
}
""", new TestParameters(options: s_options.MethodNamesArePascalCase));
}
[Fact]
public async Task TestPascalCaseMethod_NotInExplicitInterfaceImplementation()
{
await TestMissingInRegularAndScriptAsync(
"""
interface I
{
void m();
}
class C : I
{
void I.[|m|]() { }
}
""", new TestParameters(options: s_options.MethodNamesArePascalCase));
}
[Fact]
public async Task TestPascalCaseMethod_InAbstractType()
{
await TestInRegularAndScriptAsync(
"""
abstract class C
{
public abstract void [|m|]();
}
class D : C
{
public override void m() { }
}
""",
"""
abstract class C
{
public abstract void M();
}
class D : C
{
public override void M() { }
}
""",
options: s_options.MethodNamesArePascalCase);
}
[Fact]
public async Task TestPascalCaseMethod_NotInAbstractMethodImplementation()
{
await TestMissingInRegularAndScriptAsync(
"""
abstract class C
{
public abstract void m();
}
class D : C
{
public override void [|m|]() { }
}
""", new TestParameters(options: s_options.MethodNamesArePascalCase));
}
[Fact]
public async Task TestPascalCaseProperty_InInterface()
{
await TestInRegularAndScriptAsync(
"""
interface I
{
int [|p|] { get; set; }
}
class C : I
{
public int p { get { return 1; } set { } }
}
""",
"""
interface I
{
int P { get; set; }
}
class C : I
{
public int P { get { return 1; } set { } }
}
""",
options: s_options.PropertyNamesArePascalCase);
}
[Fact]
public async Task TestPascalCaseProperty_NotInImplicitInterfaceImplementation()
{
await TestMissingInRegularAndScriptAsync(
"""
interface I
{
int p { get; set; }
}
class C : I
{
public int [|p|] { get { return 1; } set { } }
}
""", new TestParameters(options: s_options.PropertyNamesArePascalCase));
}
[Fact]
public async Task TestPascalCaseMethod_OverrideInternalMethod()
{
await TestMissingInRegularAndScriptAsync(
"""
abstract class C
{
internal abstract void m();
}
class D : C
{
internal override void [|m|]() { }
}
""", new TestParameters(options: s_options.MethodNamesArePascalCase));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19106")]
public async Task TestMissingOnSymbolsWithNoName()
{
await TestMissingInRegularAndScriptAsync(
"""
namespace Microsoft.CodeAnalysis.Host
{
internal interface
[|}|]
""", new TestParameters(options: s_options.InterfaceNamesStartWithI));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17656")]
public async Task TestInterfacesStartWithIOnTypeThatAlreadyStartsWithI1()
{
await TestInRegularAndScript1Async("""
interface [|InputStream|] { }
""", """
interface IInputStream { }
""", new TestParameters(options: s_options.InterfaceNamesStartWithI));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17656")]
public async Task TestInterfacesStartWithIOnTypeThatAlreadyStartsWithI2()
{
await TestInRegularAndScript1Async("""
interface [|Stream|] { }
""", """
interface IStream { }
""", new TestParameters(options: s_options.InterfaceNamesStartWithI));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17656")]
public async Task TestInterfacesStartWithIOnTypeThatAlreadyStartsWithI3()
{
await TestMissingInRegularAndScriptAsync("""
interface [|IInputStream|] { }
""", new TestParameters(options: s_options.InterfaceNamesStartWithI));
}
#if CODE_STYLE
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/42218")]
#else
[Fact]
#endif
[WorkItem("https://github.com/dotnet/roslyn/issues/16562")]
public async Task TestRefactorNotify()
{
var markup = @"public class [|c|] { }";
var testParameters = new TestParameters(options: s_options.ClassNamesArePascalCase);
using var workspace = CreateWorkspaceFromOptions(markup, testParameters);
var (_, action) = await GetCodeActionsAsync(workspace, testParameters);
var previewOperations = await action.GetPreviewOperationsAsync(CancellationToken.None);
Assert.Empty(previewOperations.OfType<TestSymbolRenamedCodeActionOperationFactoryWorkspaceService.Operation>());
var commitOperations = await action.GetOperationsAsync(CancellationToken.None);
Assert.Equal(2, commitOperations.Length);
var symbolRenamedOperation = (TestSymbolRenamedCodeActionOperationFactoryWorkspaceService.Operation)commitOperations[1];
Assert.Equal("c", symbolRenamedOperation._symbol.Name);
Assert.Equal("C", symbolRenamedOperation._newName);
}
#if CODE_STYLE
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/42218")]
#else
[Fact]
#endif
[WorkItem("https://github.com/dotnet/roslyn/issues/38513")]
public async Task TestRefactorNotifyInterfaceNamesStartWithI()
{
var markup = @"public interface [|test|] { }";
var testParameters = new TestParameters(options: s_options.InterfaceNamesStartWithI);
using var workspace = CreateWorkspaceFromOptions(markup, testParameters);
var (_, action) = await GetCodeActionsAsync(workspace, testParameters);
var previewOperations = await action.GetPreviewOperationsAsync(CancellationToken.None);
Assert.Empty(previewOperations.OfType<TestSymbolRenamedCodeActionOperationFactoryWorkspaceService.Operation>());
var commitOperations = await action.GetOperationsAsync(CancellationToken.None);
Assert.Equal(2, commitOperations.Length);
var symbolRenamedOperation = (TestSymbolRenamedCodeActionOperationFactoryWorkspaceService.Operation)commitOperations[1];
Assert.Equal("test", symbolRenamedOperation._symbol.Name);
Assert.Equal("ITest", symbolRenamedOperation._newName);
}
#if CODE_STYLE
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/42218")]
#else
[Fact]
#endif
[WorkItem("https://github.com/dotnet/roslyn/issues/38513")]
public async Task TestRefactorNotifyTypeParameterNamesStartWithT()
{
var markup = """
public class A
{
void DoOtherThing<[|arg|]>() { }
}
""";
var testParameters = new TestParameters(options: s_options.TypeParameterNamesStartWithT);
using var workspace = CreateWorkspaceFromOptions(markup, testParameters);
var (_, action) = await GetCodeActionsAsync(workspace, testParameters);
var previewOperations = await action.GetPreviewOperationsAsync(CancellationToken.None);
Assert.Empty(previewOperations.OfType<TestSymbolRenamedCodeActionOperationFactoryWorkspaceService.Operation>());
var commitOperations = await action.GetOperationsAsync(CancellationToken.None);
Assert.Equal(2, commitOperations.Length);
var symbolRenamedOperation = (TestSymbolRenamedCodeActionOperationFactoryWorkspaceService.Operation)commitOperations[1];
Assert.Equal("arg", symbolRenamedOperation._symbol.Name);
Assert.Equal("TArg", symbolRenamedOperation._newName);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47508")]
public async Task TestRecordParameter_NoDiagnosticWhenCorrect()
{
await TestMissingInRegularAndScriptAsync(
@"record Foo(int [|MyInt|]);",
new TestParameters(options: s_options.MergeStyles(s_options.PropertyNamesArePascalCase, s_options.ParameterNamesAreCamelCaseWithPUnderscorePrefix)));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47508")]
public async Task TestRecordConstructorParameter_NoDiagnosticWhenCorrect()
{
await TestMissingInRegularAndScriptAsync(
"""
record Foo(int MyInt)
{
public Foo(string [|p_myString|]) : this(1)
{
}
}
""",
new TestParameters(options: s_options.MergeStyles(s_options.PropertyNamesArePascalCase, s_options.ParameterNamesAreCamelCaseWithPUnderscorePrefix)));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47508")]
public async Task TestRecordParameter_ParameterFormattedAsProperties()
{
await TestInRegularAndScriptAsync(
@"public record Foo(int [|myInt|]);",
@"public record Foo(int [|MyInt|]);",
options: s_options.MergeStyles(s_options.PropertyNamesArePascalCase, s_options.ParameterNamesAreCamelCaseWithPUnderscorePrefix));
}
[Theory]
[InlineData("_")]
[InlineData("_1")]
[InlineData("_123")]
[InlineData("__")]
[InlineData("___")]
public async Task TestDiscardParameterAsync(string identifier)
{
await TestMissingInRegularAndScriptAsync(
$$"""
class C
{
void M(int [|{{identifier}}|])
{
}
}
""", new TestParameters(options: s_options.ParameterNamesAreCamelCase));
}
[Theory]
[InlineData("_")]
[InlineData("_1")]
[InlineData("_123")]
[InlineData("__")]
[InlineData("___")]
public async Task TestDiscardLocalAsync(string identifier)
{
await TestMissingInRegularAndScriptAsync(
$$"""
class C
{
void M()
{
int [|{{identifier}}|] = 0;
}
}
""", new TestParameters(options: s_options.LocalNamesAreCamelCase));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49535")]
public async Task TestGlobalDirectiveAsync()
{
await TestMissingInRegularAndScriptAsync(
"""
interface I
{
int X { get; }
}
class C : I
{
int [|global::I.X|] => 0;
}
""", new TestParameters(options: s_options.PropertyNamesArePascalCase));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/50734")]
public async Task TestAsyncEntryPoint()
{
await TestMissingInRegularAndScriptAsync("""
using System.Threading.Tasks;
class C
{
static async Task [|Main|]()
{
await Task.Delay(0);
}
}
""", new TestParameters(options: s_options.AsyncFunctionNamesEndWithAsync));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49648")]
public async Task TestAsyncEntryPoint_TopLevel()
{
await TestMissingInRegularAndScriptAsync("""
using System.Threading.Tasks;
[|await Task.Delay(0);|]
""", new TestParameters(options: s_options.AsyncFunctionNamesEndWithAsync));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/51727")]
public async Task TestExternAsync()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
static extern void [|some_p_invoke()|];
}
""", new TestParameters(options: s_options.MethodNamesArePascalCase));
}
}
|