Skip to content
Permalink
Browse files

Merge pull request #39695 from dpoeschl/ConvertToLinqExtraSelect

When converting to LINQ calls, omit .Select(x => x) when possible.
  • Loading branch information...
dpoeschl committed Nov 7, 2019
2 parents 4f38fda + 507ba2d commit 10fab37775ae729f46cb27590982a381ea5bb1f1
@@ -4,6 +4,7 @@
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeActions.ConvertLinq
{
@@ -465,7 +466,7 @@ class C
IEnumerable<int> M()
{
var nums = new int[] { 1, 2, 3, 4 };
return nums.Where(x => x > 2).Select(x => x);
return nums.Where(x => x > 2);
}
}";

@@ -1327,6 +1328,44 @@ partial class C
await TestInRegularAndScriptAsync(source, linqInvocationOutput, index: 1);
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertForEachToQuery)]
[WorkItem(31784, "https://github.com/dotnet/roslyn/issues/31784")]
public async Task QueryWhichRequiresSelectManyWithIdentityLambda()
{
var source = @"
using System.Collections.Generic;
class C
{
IEnumerable<int> M()
{
[|foreach (var x in new[] { new[] { 1, 2, 3 }, new[] { 4, 5, 6 } })
{
foreach (var y in x)
{
yield return y;
}
}|]
}
}
";

var linqInvocationOutput = @"
using System.Collections.Generic;
using System.Linq;
class C
{
IEnumerable<int> M()
{
return (new[] { new[] { 1, 2, 3 }, new[] { 4, 5, 6 } }).SelectMany(x => x);
}
}
";

await TestInRegularAndScriptAsync(source, linqInvocationOutput, index: 1);
}

#endregion

#region In foreach
@@ -1612,7 +1651,7 @@ class C
IEnumerable<C> Test()
{
return (new[] { 1, 2, 3 }).Select(x => x);
return new[] { 1, 2, 3 };
}
}
";
@@ -1661,7 +1700,7 @@ class C
{
IEnumerable<int> M(IEnumerable<int> nums)
{
return nums.AsQueryable().Select(n1 => n1);
return nums.AsQueryable();
}
}";

@@ -1707,7 +1746,7 @@ class C
{
IEnumerable<int> M(IEnumerable<int> nums)
{
return nums.AsQueryable().Select(n1 => n1);
return nums.AsQueryable();
}
}";

@@ -3864,7 +3903,7 @@ class C
{
void M(IEnumerable<int> nums)
{
int c = (nums.AsQueryable().Select(n1 => n1)).Count();
int c = (nums.AsQueryable()).Count();
}
}";

@@ -4126,11 +4165,10 @@ int M(IEnumerable<int> nums)
/*21*/
return /*22*/ /* 1 *//* 2 *//* 3 *//* 4 */// 5
/*23*/
(nums /* 12 */.Select(
/* 6 *//* 7 *//* 14 */// 15
/* 9 */x /* 10 */ => x/* 10 *//*19*///20
(nums /* 12 *//* 6 *//* 7 *//* 14 */// 15
/* 9 *//* 10 *//* 10 *//*19*///20
/* 8 *//* 11 */// 13
)).Count()/* 16 *//* 17 *///18
).Count()/* 16 *//* 17 *///18
; //24
}
}";
@@ -4244,11 +4282,11 @@ void M(IEnumerable<int> nums)
/* 10 *//* 11 *//* 8*/// 9
n1 =>
/* 12 */n1 /* 13 */ > /* 14 */ 0/* 15 */// 16
).Select(
)
/* 1 *//* 2 *//* 17 */// 18
/* 3 */n1 /* 4 */=> n1/* 4 *//* 21 */// 22
/* 3 *//* 4 *//* 4 *//* 21 */// 22
/*23*//*24*//* 5 */// 7
))
)
{
/*19*/
Console.WriteLine(n1);//20
@@ -41,7 +41,7 @@ public AbstractConverter(ForEachInfo<ForEachStatementSyntax, StatementSyntax> fo
{
return convertToQuery
? CreateQueryExpression(selectExpression, leadingTokensForSelect, trailingTokensForSelect)
: (ExpressionSyntax)CreateLinqInvocation(selectExpression, leadingTokensForSelect, trailingTokensForSelect);
: (ExpressionSyntax)CreateLinqInvocationOrSimpleExpression(selectExpression, leadingTokensForSelect, trailingTokensForSelect);
}

/// <summary>
@@ -120,7 +120,7 @@ private static QueryClauseSyntax CreateQueryClause(ExtendedSyntaxNode node)
/// <param name="leadingTokensForSelect">extra leading tokens to be added to the select clause</param>
/// <param name="trailingTokensForSelect">extra trailing tokens to be added to the select clause</param>
/// <returns></returns>
private InvocationExpressionSyntax CreateLinqInvocation(
private ExpressionSyntax CreateLinqInvocationOrSimpleExpression(
ExpressionSyntax selectExpression,
IEnumerable<SyntaxToken> leadingTokensForSelect,
IEnumerable<SyntaxToken> trailingTokensForSelect)
@@ -129,7 +129,7 @@ private static QueryClauseSyntax CreateQueryClause(ExtendedSyntaxNode node)
selectExpression = selectExpression.WithCommentsFrom(leadingTokensForSelect, ForEachInfo.TrailingTokens.Concat(trailingTokensForSelect));
var currentExtendedNodeIndex = 0;

return CreateLinqInvocation(
return CreateLinqInvocationOrSimpleExpression(
foreachStatement,
receiverForInvocation: foreachStatement.Expression,
selectExpression: selectExpression,
@@ -139,7 +139,7 @@ private static QueryClauseSyntax CreateQueryClause(ExtendedSyntaxNode node)
.WithAdditionalAnnotations(Formatter.Annotation);
}

private InvocationExpressionSyntax CreateLinqInvocation(
private ExpressionSyntax CreateLinqInvocationOrSimpleExpression(
ForEachStatementSyntax forEachStatement,
ExpressionSyntax receiverForInvocation,
IEnumerable<SyntaxTrivia> leadingCommentsTrivia,
@@ -183,7 +183,25 @@ private static QueryClauseSyntax CreateQueryClause(ExtendedSyntaxNode node)
// OR
// c1.SelectMany(n1 => ...
//

var invokedMethodName = !hasForEachChild ? nameof(Enumerable.Select) : nameof(Enumerable.SelectMany);

// Avoid `.Select(x => x)`
if (invokedMethodName == nameof(Enumerable.Select) &&
lambdaBody is IdentifierNameSyntax identifier &&
identifier.Identifier.ValueText == forEachStatement.Identifier.ValueText)
{
// Because we're dropping the lambda, any comments associated with it need to be preserved.

var droppedTrivia = new List<SyntaxTrivia>();
foreach (var token in lambda.DescendantTokens())
{
droppedTrivia.AddRange(token.GetAllTrivia().Where(t => !t.IsWhitespace()));
}

return receiverForInvocation.WithAppendedTrailingTrivia(droppedTrivia);
}

return SyntaxFactory.InvocationExpression(
SyntaxFactory.MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
@@ -232,7 +250,7 @@ private static QueryClauseSyntax CreateQueryClause(ExtendedSyntaxNode node)
hasForEachChild = true;
var foreachStatement = (ForEachStatementSyntax)node.Node;
++extendedNodeIndex;
return CreateLinqInvocation(
return CreateLinqInvocationOrSimpleExpression(
foreachStatement,
receiverForInvocation: foreachStatement.Expression,
selectExpression: selectExpression,

0 comments on commit 10fab37

Please sign in to comment.
You can’t perform that action at this time.