Skip to content

Commit

Permalink
Preserve code style during fix
Browse files Browse the repository at this point in the history
Fixes #7098
  • Loading branch information
sharwell committed Dec 27, 2023
1 parent 5dc99c6 commit ff8c0c0
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,6 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
var editor = await DocumentEditor.CreateAsync(document, ct).ConfigureAwait(false);
var generator = editor.Generator;

var tryGetValueAccess = generator.MemberAccessExpression(containsKeyAccess.Expression, TryGetValue);
var keyArgument = containsKeyInvocation.ArgumentList.Arguments.FirstOrDefault();

// Roslyn has reducers that are run after a code action is applied, one of which will
// simplify a TypeSyntax to `var` if the user prefers that. So we generate TypeSyntax, add
// simplifier annotation, and then let Roslyn decide whether to keep TypeSyntax or convert it to var.
Expand All @@ -119,13 +116,16 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
typeSyntax = IdentifierName(Var);
}

var outArgument = generator.Argument(RefKind.Out,
var outArgument = (ArgumentSyntax)generator.Argument(RefKind.Out,
DeclarationExpression(
typeSyntax,
SingleVariableDesignation(Identifier(Value))
)
);
var tryGetValueInvocation = generator.InvocationExpression(tryGetValueAccess, keyArgument, outArgument);

var tryGetValueInvocation = containsKeyInvocation
.ReplaceNode(containsKeyAccess.Name, IdentifierName(TryGetValue).WithTriviaFrom(containsKeyAccess.Name))
.AddArgumentListArguments(outArgument);
editor.ReplaceNode(containsKeyInvocation, tryGetValueInvocation);

var identifierName = (IdentifierNameSyntax)generator.IdentifierName(Value);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.Globalization;
Expand Down Expand Up @@ -1605,6 +1605,55 @@ public void Test(int key, string text) {
return VerifyCS.VerifyCodeFixAsync(code, diagnostic, fixedCode);
}

[Fact]
[WorkItem(7098, "https://github.com/dotnet/roslyn-analyzers/issues/7098")]
public async Task CodeFixPreservesStyle()
{
const string code =
"""
using System.Collections.Generic;
namespace UnitTests {
class Program {
Dictionary<int, string> dictionary = new();
public void Test(int key, string text) {
if({|#0:this.dictionary.ContainsKey(key)|} && !string.IsNullOrEmpty(text)) {
text = {|#1:dictionary[key]|};
}
}
}
}
""";
const string fixedCode =
"""
using System.Collections.Generic;
namespace UnitTests {
class Program {
Dictionary<int, string> dictionary = new();
public void Test(int key, string text) {
if(this.dictionary.TryGetValue(key, out string value) && !string.IsNullOrEmpty(text)) {
text = value;
}
}
}
}
""";

await new VerifyCS.Test
{
LanguageVersion = LanguageVersion.CSharp9,
TestCode = code,
FixedCode = fixedCode,
ExpectedDiagnostics =
{
VerifyCS.Diagnostic(PreferDictionaryTryMethodsOverContainsKeyGuardAnalyzer.PreferTryGetValueDiagnostic)
.WithLocation(0)
.WithLocation(1),
},
}.RunAsync();
}

private static string CreateCSharpCode(string content)
{
return string.Format(CultureInfo.InvariantCulture, CSharpTemplate, content);
Expand Down

0 comments on commit ff8c0c0

Please sign in to comment.