Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [CLI] Spellcheck file names ([PR](https://github.com/dotnet/roslynator/pull/1368))
- `roslynator spellcheck --scope file-name`

### Changed

- Update analyzer [RCS1197](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1197) ([PR](https://github.com/dotnet/roslynator/pull/1370))
- Do not report interpolated string and string concatenation

### Fixed

- Fix analyzer [RCS1055](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1055) ([PR](https://github.com/dotnet/roslynator/pull/1361))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslynator.CodeFixes;
using Roslynator.CSharp.Refactorings;
using Roslynator.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using static Roslynator.CSharp.CSharpFactory;
Expand Down Expand Up @@ -94,83 +93,19 @@ public static async Task<Document> RefactorAsync(
SimpleMemberInvocationExpressionInfo invocationInfo,
CancellationToken cancellationToken)
{
SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

InvocationExpressionSyntax invocation = invocationInfo.InvocationExpression;
InvocationExpressionSyntax newInvocation;

bool isAppendLine = string.Equals(invocationInfo.NameText, "AppendLine", StringComparison.Ordinal);

ExpressionSyntax expression = argument.Expression;

switch (expression.Kind())
{
case SyntaxKind.InterpolatedStringExpression:
{
newInvocation = ConvertInterpolatedStringExpressionToInvocationExpression((InterpolatedStringExpressionSyntax)expression, invocationInfo, semanticModel);
break;
}
case SyntaxKind.AddExpression:
{
ImmutableArray<ExpressionSyntax> expressions = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)expression)
.AsChain()
.ToImmutableArray();

newInvocation = invocation
.ReplaceNode(invocationInfo.Name, IdentifierName("Append").WithTriviaFrom(invocationInfo.Name))
.WithArgumentList(invocation.ArgumentList.WithArguments(SingletonSeparatedList(Argument(ReplaceStringLiteralWithCharacterLiteral(expressions[0])))).WithoutTrailingTrivia());

for (int i = 1; i < expressions.Length; i++)
{
ExpressionSyntax argumentExpression = expressions[i];

string methodName;
if (i == expressions.Length - 1
&& isAppendLine
&& semanticModel
.GetTypeInfo(argumentExpression, cancellationToken)
.ConvertedType?
.SpecialType == SpecialType.System_String)
{
methodName = "AppendLine";
}
else
{
methodName = "Append";

argumentExpression = ReplaceStringLiteralWithCharacterLiteral(argumentExpression);
}

newInvocation = SimpleMemberInvocationExpression(
newInvocation,
IdentifierName(methodName),
ArgumentList(Argument(argumentExpression)));

if (i == expressions.Length - 1
&& isAppendLine
&& !string.Equals(methodName, "AppendLine", StringComparison.Ordinal))
{
newInvocation = SimpleMemberInvocationExpression(
newInvocation,
IdentifierName("AppendLine"),
ArgumentList());
}
}

break;
}
default:
{
newInvocation = CreateInvocationExpression(
(InvocationExpressionSyntax)expression,
invocation);
newInvocation = CreateInvocationExpression(
(InvocationExpressionSyntax)expression,
invocation);

if (isAppendLine)
newInvocation = SimpleMemberInvocationExpression(newInvocation, IdentifierName("AppendLine"), ArgumentList());

break;
}
}
if (isAppendLine)
newInvocation = SimpleMemberInvocationExpression(newInvocation, IdentifierName("AppendLine"), ArgumentList());

newInvocation = newInvocation
.WithTriviaFrom(invocation)
Expand All @@ -179,68 +114,6 @@ public static async Task<Document> RefactorAsync(
return await document.ReplaceNodeAsync(invocation, newInvocation, cancellationToken).ConfigureAwait(false);
}

private static InvocationExpressionSyntax ConvertInterpolatedStringExpressionToInvocationExpression(
InterpolatedStringExpressionSyntax interpolatedString,
in SimpleMemberInvocationExpressionInfo invocationInfo,
SemanticModel semanticModel)
{
bool isVerbatim = interpolatedString.IsVerbatim();

bool isAppendLine = string.Equals(invocationInfo.NameText, "AppendLine", StringComparison.Ordinal);

InvocationExpressionSyntax invocation = invocationInfo.InvocationExpression;

InvocationExpressionSyntax newExpression = null;

SyntaxList<InterpolatedStringContentSyntax> contents = interpolatedString.Contents;

for (int i = 0; i < contents.Count; i++)
{
(SyntaxKind contentKind, string methodName, ImmutableArray<ArgumentSyntax> arguments) = ConvertInterpolatedStringToStringBuilderMethodRefactoring.Refactor(contents[i], isVerbatim);

if (i == contents.Count - 1
&& isAppendLine
&& string.Equals(methodName, "Append", StringComparison.Ordinal)
&& (contentKind == SyntaxKind.InterpolatedStringText
|| semanticModel.IsImplicitConversion(((InterpolationSyntax)contents[i]).Expression, semanticModel.Compilation.GetSpecialType(SpecialType.System_String))))
{
methodName = "AppendLine";
}
else if (methodName == "Append")
{
arguments = ReplaceStringLiteralWithCharacterLiteral(arguments);
}

if (newExpression is null)
{
arguments = arguments.Replace(arguments[0], arguments[0].WithLeadingTrivia(interpolatedString.GetLeadingTrivia()));

newExpression = invocation
.ReplaceNode(invocationInfo.Name, IdentifierName(methodName).WithTriviaFrom(invocationInfo.Name))
.WithArgumentList(invocation.ArgumentList.WithArguments(arguments.ToSeparatedSyntaxList()).WithoutTrailingTrivia());
}
else
{
newExpression = SimpleMemberInvocationExpression(
newExpression,
IdentifierName(methodName),
ArgumentList(arguments.ToSeparatedSyntaxList()));
}

if (i == contents.Count - 1
&& isAppendLine
&& !string.Equals(methodName, "AppendLine", StringComparison.Ordinal))
{
newExpression = SimpleMemberInvocationExpression(
newExpression,
IdentifierName("AppendLine"),
ArgumentList());
}
}

return newExpression;
}

private static InvocationExpressionSyntax CreateInvocationExpression(
InvocationExpressionSyntax innerInvocationExpression,
InvocationExpressionSyntax outerInvocationExpression)
Expand Down Expand Up @@ -317,37 +190,4 @@ private static InvocationExpressionSyntax CreateNewInvocationExpression(Invocati
.WithExpression(memberAccess.WithName(IdentifierName(methodName).WithTriviaFrom(memberAccess.Name)))
.WithArgumentList(argumentList);
}

private static ExpressionSyntax ReplaceStringLiteralWithCharacterLiteral(ExpressionSyntax expression)
{
if (expression.IsKind(SyntaxKind.StringLiteralExpression))
{
var literalExpression = (LiteralExpressionSyntax)expression;

if (literalExpression.Token.ValueText.Length == 1)
return SyntaxRefactorings.ReplaceStringLiteralWithCharacterLiteral(literalExpression);
}

return expression;
}

private static ImmutableArray<ArgumentSyntax> ReplaceStringLiteralWithCharacterLiteral(ImmutableArray<ArgumentSyntax> arguments)
{
ArgumentSyntax argument = arguments.SingleOrDefault(shouldThrow: false);

if (argument is not null)
{
ExpressionSyntax expression = argument.Expression;

if (expression is not null)
{
ExpressionSyntax newExpression = ReplaceStringLiteralWithCharacterLiteral(expression);

if (newExpression != expression)
arguments = arguments.Replace(argument, argument.WithExpression(newExpression));
}
}

return arguments;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,33 +69,6 @@ public static void Analyze(SyntaxNodeAnalysisContext context, in SimpleMemberInv

SyntaxKind expressionKind = expression.Kind();

switch (expressionKind)
{
case SyntaxKind.InterpolatedStringExpression:
{
if (((CSharpCompilation)context.Compilation).LanguageVersion <= LanguageVersion.CSharp9
|| !context.SemanticModel.HasConstantValue(expression, context.CancellationToken))
{
ReportDiagnostic(argument);
}

return;
}
case SyntaxKind.AddExpression:
{
BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)expression);

if (binaryExpressionInfo.Success
&& binaryExpressionInfo.AsChain().Reverse().IsStringConcatenation(context.SemanticModel, context.CancellationToken)
&& !context.SemanticModel.GetConstantValue(expression, context.CancellationToken).HasValue)
{
ReportDiagnostic(argument);
}

return;
}
}

if (expressionKind != SyntaxKind.InvocationExpression)
return;

Expand Down
Loading