Skip to content
Draft
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<diagnostics severity="Info">
<group id="WTG3014" message="Don't use Concat when prepending a single element to an enumerable.">
<diagnostic>
<location>Test0.cs: (10, 3-36)</location>
</diagnostic>
<diagnostic>
<location>Test0.cs: (11, 3-20)</location>
</diagnostic>
</group>
<group id="WTG3013" message="Don't use Concat when appending a single element to an enumerable.">
<diagnostic>
<location>Test0.cs: (12, 3-25)</location>
</diagnostic>
<diagnostic>
<location>Test0.cs: (13, 3-20)</location>
</diagnostic>
</group>
</diagnostics>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Linq;

public class Bob
{
public void Method()
{
var viewModel = new ViewModel();

viewModel.Items.Prepend<object>(viewModel);
Enumerable.Prepend<object>(viewModel.Items, viewModel);
viewModel.Items.Append<object>(viewModel);
Enumerable.Append<object>(viewModel.Items, viewModel);
}
}

public class ViewModel
{
public IEnumerable<ViewModel> Items { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Linq;

public class Bob
{
public void Method()
{
var viewModel = new ViewModel();

new object[] { viewModel }.Concat(viewModel.Items);
Enumerable.Concat(new object[] { viewModel }, viewModel.Items);
viewModel.Items.Concat(new object[] { viewModel });
Enumerable.Concat(viewModel.Items, new object[] { viewModel });
}
}

public class ViewModel
{
public IEnumerable<ViewModel> Items { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,19 @@ public static SyntaxNode FixConcatWithAppendMethod(MemberAccessExpressionSyntax

var listOfArgumentsAndSeparators = new List<SyntaxNodeOrToken>();

ExpressionSyntax singleElementCollection;

switch (invocation.ArgumentList.Arguments.Count)
{
case 1:
listOfArgumentsAndSeparators.Add(Argument(LinqEnumerableUtils.GetFirstValue(invocation.ArgumentList.Arguments[0].Expression)!));
singleElementCollection = invocation.ArgumentList.Arguments[0].Expression;
listOfArgumentsAndSeparators.Add(Argument(LinqEnumerableUtils.GetFirstValue(singleElementCollection)!));
break;
case 2:
singleElementCollection = invocation.ArgumentList.Arguments[1].Expression;
listOfArgumentsAndSeparators.Add(invocation.ArgumentList.Arguments[0]);
listOfArgumentsAndSeparators.Add(Token(SyntaxKind.CommaToken));
listOfArgumentsAndSeparators.Add(Argument(LinqEnumerableUtils.GetFirstValue(invocation.ArgumentList.Arguments[1].Expression)!));
listOfArgumentsAndSeparators.Add(Argument(LinqEnumerableUtils.GetFirstValue(singleElementCollection)!));
break;
default:
throw new InvalidOperationException("Unreachable - Code fix should never trigger for >2 arguments.");
Expand All @@ -125,7 +129,7 @@ public static SyntaxNode FixConcatWithAppendMethod(MemberAccessExpressionSyntax
.WithTriviaFrom(m.Expression)
.WithAdditionalAnnotations(Simplifier.Annotation),
m.OperatorToken,
IdentifierName(nameof(Enumerable.Append))
GetMethodName(nameof(Enumerable.Append), singleElementCollection)
.WithTriviaFrom(m.Name)))
.WithArgumentList(
ArgumentList(
Expand All @@ -141,19 +145,22 @@ public static SyntaxNode FixConcatWithAppendMethod(MemberAccessExpressionSyntax
var listOfArgumentsAndSeparators = new List<SyntaxNodeOrToken>();

ExpressionSyntax member;
ExpressionSyntax singleElementCollection;

switch (invocation.ArgumentList.Arguments.Count)
{
case 1:
listOfArgumentsAndSeparators.Add(Argument(LinqEnumerableUtils.GetFirstValue(m.Expression.TryGetExpressionFromParenthesizedExpression())!));
singleElementCollection = m.Expression.TryGetExpressionFromParenthesizedExpression();
listOfArgumentsAndSeparators.Add(Argument(LinqEnumerableUtils.GetFirstValue(singleElementCollection)!));
member = ParenthesizedExpression(invocation.ArgumentList.Arguments[0].Expression.WithoutTrivia())
.WithTriviaFrom(m.Expression)
.WithAdditionalAnnotations(Simplifier.Annotation);
break;
case 2:
singleElementCollection = invocation.ArgumentList.Arguments[0].Expression;
listOfArgumentsAndSeparators.Add(invocation.ArgumentList.Arguments[1]);
listOfArgumentsAndSeparators.Add(Token(SyntaxKind.CommaToken));
listOfArgumentsAndSeparators.Add(Argument(LinqEnumerableUtils.GetFirstValue(invocation.ArgumentList.Arguments[0].Expression)!));
listOfArgumentsAndSeparators.Add(Argument(LinqEnumerableUtils.GetFirstValue(singleElementCollection)!));
member = m.Expression;
break;

Expand All @@ -166,7 +173,7 @@ public static SyntaxNode FixConcatWithAppendMethod(MemberAccessExpressionSyntax
SyntaxKind.SimpleMemberAccessExpression,
member,
m.OperatorToken,
IdentifierName(nameof(Enumerable.Prepend))
GetMethodName(nameof(Enumerable.Prepend), singleElementCollection)
.WithTriviaFrom(m.Name)))
.WithArgumentList(
ArgumentList(
Expand Down Expand Up @@ -213,5 +220,42 @@ public static SyntaxNode FixConcatWithNewCollection(MemberAccessExpressionSyntax
.WithTriviaFrom(invocation)
.WithAdditionalAnnotations(Simplifier.Annotation);
}

static SimpleNameSyntax GetMethodName(string methodName, ExpressionSyntax singleElementCollection)
{
var elementType = GetCollectionElementType(singleElementCollection.TryGetExpressionFromParenthesizedExpression());

if (elementType != null)
{
return GenericName(Identifier(methodName))
.WithTypeArgumentList(
TypeArgumentList(
SingletonSeparatedList<TypeSyntax>(
elementType.WithoutTrivia())))
.WithAdditionalAnnotations(Simplifier.Annotation);
}

return IdentifierName(methodName);
}

static TypeSyntax? GetCollectionElementType(ExpressionSyntax expression)
{
switch (expression.Kind())
{
case SyntaxKind.ArrayCreationExpression:
return ((ArrayCreationExpressionSyntax)expression).Type.ElementType;

case SyntaxKind.ObjectCreationExpression:
var objectCreationType = ((ObjectCreationExpressionSyntax)expression).Type;
if (objectCreationType is GenericNameSyntax genericName && genericName.TypeArgumentList.Arguments.Count == 1)
{
return genericName.TypeArgumentList.Arguments[0];
}

break;
}

return null;
}
}
}