Skip to content

Commit

Permalink
UpdateStringFormatToFormattableString now deals with escaped characters.
Browse files Browse the repository at this point in the history
  • Loading branch information
manfred-brands committed Oct 28, 2023
1 parent 62572d1 commit 3b57fd2
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Gu.Roslyn.Asserts;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using NUnit.Analyzers.Constants;
using NUnit.Analyzers.UpdateStringFormatToInterpolatableString;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,24 @@ public void ConvertWhenMinimumParametersIsTwo()
");
RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode);
}

// We need to double the backslashes as the text is formatted and we want the code to contain \n and not LF
[TestCase("Passed: {0}")]
[TestCase("Passed: {0} {{")]
[TestCase("Passed: {{{0}}}")]
[TestCase("{{{0}}}")]
[TestCase("Passed: \\\"{0}\\\"")]
[TestCase("Passed:\\n{0}")]
[TestCase("Passed:\\t\\\"{0}\\\"")]
public void TestConvertWithEmbeddedSpecialCharacters(string text)
{
var code = TestUtility.WrapInTestMethod($"↓Assert.Pass(\"{text}\", 42);");

string interpolatableText = text.Replace("{0}", "{42}");
var fixedCode = TestUtility.WrapInTestMethod($"Assert.Pass($\"{interpolatableText}\");");

RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode);
}
}
}
#endif
24 changes: 19 additions & 5 deletions src/nunit.analyzers/Helpers/CodeFixHelper.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
Expand Down Expand Up @@ -74,7 +72,7 @@ public static void UpdateStringFormatToFormattableString(List<ArgumentSyntax> ar
SyntaxFactory.Token(SyntaxKind.InterpolatedStringStartToken),
SyntaxFactory.List(interpolatedStringContent));

// Replace format specificatio argument with interpolated string.
// Replace format specification argument with interpolated string.
arguments[minimumNumberOfArguments] = SyntaxFactory.Argument(interpolatedString);

// Delete params arguments.
Expand All @@ -85,7 +83,7 @@ public static void UpdateStringFormatToFormattableString(List<ArgumentSyntax> ar
internal static IEnumerable<InterpolatedStringContentSyntax> UpdateStringFormatToFormattableString(string formatSpecification, ExpressionSyntax[] formatArguments)
{
int startIndex = 0;
for (; ;)
for (; startIndex < formatSpecification.Length;)
{
int argumentSpecification = formatSpecification.IndexOf('{', startIndex);
if (argumentSpecification < 0)
Expand All @@ -95,6 +93,15 @@ internal static IEnumerable<InterpolatedStringContentSyntax> UpdateStringFormatT
yield return SyntaxFactory.InterpolatedStringText(InterpolatedStringTextToken(text));
break;
}
else if (argumentSpecification + 1 < formatSpecification.Length &&
formatSpecification[argumentSpecification + 1] == '{')
{
// Special case, double '{' is an escaped '{' and should be treated as text.
argumentSpecification += 2;
string text = formatSpecification.Substring(startIndex, argumentSpecification - startIndex);
yield return SyntaxFactory.InterpolatedStringText(InterpolatedStringTextToken(text));
startIndex = argumentSpecification;
}
else
{
if (argumentSpecification > startIndex)
Expand Down Expand Up @@ -165,7 +172,14 @@ internal static IEnumerable<InterpolatedStringContentSyntax> UpdateStringFormatT

private static SyntaxToken InterpolatedStringTextToken(string text)
{
return SyntaxFactory.Token(SyntaxTriviaList.Empty, SyntaxKind.InterpolatedStringTextToken, text, text, SyntaxTriviaList.Empty);
// FormatLiteral doesn't escape double quotes when passing in quote: false
// It does when passing in quote: true but then it also surrounds it with double quotes.
// So we do that replacement ourselves.
string escapedText = SymbolDisplay.FormatLiteral(text, false)
.Replace("\"", "\\\"");

return SyntaxFactory.Token(SyntaxTriviaList.Empty, SyntaxKind.InterpolatedStringTextToken,
escapedText, text, SyntaxTriviaList.Empty);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ protected override void AnalyzeAssertInvocation(Version nunitVersion, OperationA
{
if (nunitVersion.Major >= 4)
{
// Too late, this won't work as the method with the `params` doesn't exit
// Too late, this won't work as the method with the `params` parameter doesn't exists
// and won't be resolved by the compiler.
return;
}
Expand Down

0 comments on commit 3b57fd2

Please sign in to comment.