444 lines
15 KiB
C#
444 lines
15 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using Roslyn.Utilities;
|
|
|
|
namespace Microsoft.CodeAnalysis.CSharp;
|
|
|
|
internal static class LambdaUtilities
|
|
{
|
|
public static bool IsLambda(SyntaxNode node)
|
|
{
|
|
switch (node.Kind())
|
|
{
|
|
case SyntaxKind.AnonymousMethodExpression:
|
|
case SyntaxKind.SimpleLambdaExpression:
|
|
case SyntaxKind.ParenthesizedLambdaExpression:
|
|
case SyntaxKind.LetClause:
|
|
case SyntaxKind.JoinClause:
|
|
case SyntaxKind.WhereClause:
|
|
case SyntaxKind.AscendingOrdering:
|
|
case SyntaxKind.DescendingOrdering:
|
|
case SyntaxKind.GroupClause:
|
|
case SyntaxKind.LocalFunctionStatement:
|
|
return true;
|
|
case SyntaxKind.SelectClause:
|
|
{
|
|
SelectClauseSyntax selectClauseSyntax = (SelectClauseSyntax)(object)node;
|
|
return !IsReducedSelectOrGroupByClause(selectClauseSyntax, selectClauseSyntax.Expression);
|
|
}
|
|
case SyntaxKind.FromClause:
|
|
return !node.Parent.IsKind(SyntaxKind.QueryExpression);
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static bool IsNotLambda(SyntaxNode node)
|
|
{
|
|
return !IsLambda(node);
|
|
}
|
|
|
|
public static SyntaxNode GetLambda(SyntaxNode lambdaBody)
|
|
{
|
|
SyntaxNode parent = lambdaBody.Parent;
|
|
if (parent.IsKind(SyntaxKind.ArrowExpressionClause))
|
|
{
|
|
parent = parent.Parent;
|
|
}
|
|
return parent;
|
|
}
|
|
|
|
internal static SyntaxNode? TryGetCorrespondingLambdaBody(SyntaxNode oldBody, SyntaxNode newLambda)
|
|
{
|
|
switch (newLambda.Kind())
|
|
{
|
|
case SyntaxKind.AnonymousMethodExpression:
|
|
case SyntaxKind.SimpleLambdaExpression:
|
|
case SyntaxKind.ParenthesizedLambdaExpression:
|
|
return (SyntaxNode?)(object)((AnonymousFunctionExpressionSyntax)(object)newLambda).Body;
|
|
case SyntaxKind.FromClause:
|
|
return (SyntaxNode?)(object)((FromClauseSyntax)(object)newLambda).Expression;
|
|
case SyntaxKind.LetClause:
|
|
return (SyntaxNode?)(object)((LetClauseSyntax)(object)newLambda).Expression;
|
|
case SyntaxKind.WhereClause:
|
|
return (SyntaxNode?)(object)((WhereClauseSyntax)(object)newLambda).Condition;
|
|
case SyntaxKind.AscendingOrdering:
|
|
case SyntaxKind.DescendingOrdering:
|
|
return (SyntaxNode?)(object)((OrderingSyntax)(object)newLambda).Expression;
|
|
case SyntaxKind.SelectClause:
|
|
{
|
|
SelectClauseSyntax selectClauseSyntax = (SelectClauseSyntax)(object)newLambda;
|
|
if (!IsReducedSelectOrGroupByClause(selectClauseSyntax, selectClauseSyntax.Expression))
|
|
{
|
|
return (SyntaxNode?)(object)selectClauseSyntax.Expression;
|
|
}
|
|
return null;
|
|
}
|
|
case SyntaxKind.JoinClause:
|
|
{
|
|
JoinClauseSyntax obj2 = (JoinClauseSyntax)(object)oldBody.Parent;
|
|
JoinClauseSyntax joinClauseSyntax = (JoinClauseSyntax)(object)newLambda;
|
|
if ((object)obj2.LeftExpression != oldBody)
|
|
{
|
|
return (SyntaxNode?)(object)joinClauseSyntax.RightExpression;
|
|
}
|
|
return (SyntaxNode?)(object)joinClauseSyntax.LeftExpression;
|
|
}
|
|
case SyntaxKind.GroupClause:
|
|
{
|
|
GroupClauseSyntax obj = (GroupClauseSyntax)(object)oldBody.Parent;
|
|
GroupClauseSyntax groupClauseSyntax = (GroupClauseSyntax)(object)newLambda;
|
|
if ((object)obj.GroupExpression != oldBody)
|
|
{
|
|
return (SyntaxNode?)(object)groupClauseSyntax.ByExpression;
|
|
}
|
|
if (!IsReducedSelectOrGroupByClause(groupClauseSyntax, groupClauseSyntax.GroupExpression))
|
|
{
|
|
return (SyntaxNode?)(object)groupClauseSyntax.GroupExpression;
|
|
}
|
|
return null;
|
|
}
|
|
case SyntaxKind.LocalFunctionStatement:
|
|
return GetLocalFunctionBody((LocalFunctionStatementSyntax)(object)newLambda);
|
|
default:
|
|
throw ExceptionUtilities.UnexpectedValue((object)newLambda.Kind());
|
|
}
|
|
}
|
|
|
|
public static SyntaxNode GetNestedFunctionBody(SyntaxNode nestedFunction)
|
|
{
|
|
if (!(nestedFunction is AnonymousFunctionExpressionSyntax anonymousFunctionExpressionSyntax))
|
|
{
|
|
if (nestedFunction is LocalFunctionStatementSyntax localFunctionStatementSyntax)
|
|
{
|
|
return (SyntaxNode)(((object)localFunctionStatementSyntax.Body) ?? ((object)localFunctionStatementSyntax.ExpressionBody.Expression));
|
|
}
|
|
throw ExceptionUtilities.UnexpectedValue((object)nestedFunction);
|
|
}
|
|
return (SyntaxNode)(object)anonymousFunctionExpressionSyntax.Body;
|
|
}
|
|
|
|
public static bool IsNotLambdaBody(SyntaxNode node)
|
|
{
|
|
return !IsLambdaBody(node);
|
|
}
|
|
|
|
public static bool IsLambdaBody(SyntaxNode node, bool allowReducedLambdas = false)
|
|
{
|
|
SyntaxNode val = ((node != null) ? node.Parent : null);
|
|
if (val == null)
|
|
{
|
|
return false;
|
|
}
|
|
switch (val.Kind())
|
|
{
|
|
case SyntaxKind.AnonymousMethodExpression:
|
|
case SyntaxKind.SimpleLambdaExpression:
|
|
case SyntaxKind.ParenthesizedLambdaExpression:
|
|
return (object)((AnonymousFunctionExpressionSyntax)(object)val).Body == node;
|
|
case SyntaxKind.LocalFunctionStatement:
|
|
return (object)((LocalFunctionStatementSyntax)(object)val).Body == node;
|
|
case SyntaxKind.ArrowExpressionClause:
|
|
{
|
|
ArrowExpressionClauseSyntax arrowExpressionClauseSyntax = (ArrowExpressionClauseSyntax)(object)val;
|
|
if ((object)arrowExpressionClauseSyntax.Expression == node)
|
|
{
|
|
return arrowExpressionClauseSyntax.Parent is LocalFunctionStatementSyntax;
|
|
}
|
|
return false;
|
|
}
|
|
case SyntaxKind.FromClause:
|
|
{
|
|
FromClauseSyntax fromClauseSyntax = (FromClauseSyntax)(object)val;
|
|
if ((object)fromClauseSyntax.Expression == node)
|
|
{
|
|
return fromClauseSyntax.Parent is QueryBodySyntax;
|
|
}
|
|
return false;
|
|
}
|
|
case SyntaxKind.JoinClause:
|
|
{
|
|
JoinClauseSyntax joinClauseSyntax = (JoinClauseSyntax)(object)val;
|
|
if ((object)joinClauseSyntax.LeftExpression != node)
|
|
{
|
|
return (object)joinClauseSyntax.RightExpression == node;
|
|
}
|
|
return true;
|
|
}
|
|
case SyntaxKind.LetClause:
|
|
return (object)((LetClauseSyntax)(object)val).Expression == node;
|
|
case SyntaxKind.WhereClause:
|
|
return (object)((WhereClauseSyntax)(object)val).Condition == node;
|
|
case SyntaxKind.AscendingOrdering:
|
|
case SyntaxKind.DescendingOrdering:
|
|
return (object)((OrderingSyntax)(object)val).Expression == node;
|
|
case SyntaxKind.SelectClause:
|
|
{
|
|
SelectClauseSyntax selectClauseSyntax = (SelectClauseSyntax)(object)val;
|
|
if ((object)selectClauseSyntax.Expression == node)
|
|
{
|
|
if (!allowReducedLambdas)
|
|
{
|
|
return !IsReducedSelectOrGroupByClause(selectClauseSyntax, selectClauseSyntax.Expression);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
case SyntaxKind.GroupClause:
|
|
{
|
|
GroupClauseSyntax groupClauseSyntax = (GroupClauseSyntax)(object)val;
|
|
if ((object)groupClauseSyntax.GroupExpression != node || (!allowReducedLambdas && IsReducedSelectOrGroupByClause(groupClauseSyntax, groupClauseSyntax.GroupExpression)))
|
|
{
|
|
return (object)groupClauseSyntax.ByExpression == node;
|
|
}
|
|
return true;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static bool IsReducedSelectOrGroupByClause(SelectOrGroupClauseSyntax selectOrGroupClause, ExpressionSyntax selectOrGroupExpression)
|
|
{
|
|
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
|
|
if (!((SyntaxNode?)(object)selectOrGroupExpression).IsKind(SyntaxKind.IdentifierName))
|
|
{
|
|
return false;
|
|
}
|
|
SyntaxToken identifier = ((IdentifierNameSyntax)selectOrGroupExpression).Identifier;
|
|
CSharpSyntaxNode parent = selectOrGroupClause.Parent.Parent;
|
|
QueryBodySyntax body;
|
|
SyntaxToken identifier2;
|
|
if (((SyntaxNode?)(object)parent).IsKind(SyntaxKind.QueryExpression))
|
|
{
|
|
QueryExpressionSyntax obj = (QueryExpressionSyntax)parent;
|
|
body = obj.Body;
|
|
identifier2 = obj.FromClause.Identifier;
|
|
}
|
|
else
|
|
{
|
|
QueryContinuationSyntax obj2 = (QueryContinuationSyntax)parent;
|
|
identifier2 = obj2.Identifier;
|
|
body = obj2.Body;
|
|
}
|
|
if (!SyntaxFactory.AreEquivalent(identifier2, identifier))
|
|
{
|
|
return false;
|
|
}
|
|
if (((SyntaxNode?)(object)selectOrGroupClause).IsKind(SyntaxKind.SelectClause) && body.Clauses.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
Enumerator<QueryClauseSyntax> enumerator = body.Clauses.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
QueryClauseSyntax current = enumerator.Current;
|
|
if (!((SyntaxNode?)(object)current).IsKind(SyntaxKind.WhereClause) && !((SyntaxNode?)(object)current).IsKind(SyntaxKind.OrderByClause))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool IsLambdaBodyStatementOrExpression(SyntaxNode node)
|
|
{
|
|
return IsLambdaBody(node);
|
|
}
|
|
|
|
public static bool IsLambdaBodyStatementOrExpression(SyntaxNode node, out SyntaxNode lambdaBody)
|
|
{
|
|
lambdaBody = node;
|
|
return IsLambdaBody(node);
|
|
}
|
|
|
|
public static bool TryGetLambdaBodies(SyntaxNode node, [NotNullWhen(true)] out SyntaxNode? lambdaBody1, out SyntaxNode? lambdaBody2)
|
|
{
|
|
lambdaBody1 = null;
|
|
lambdaBody2 = null;
|
|
switch (node.Kind())
|
|
{
|
|
case SyntaxKind.AnonymousMethodExpression:
|
|
case SyntaxKind.SimpleLambdaExpression:
|
|
case SyntaxKind.ParenthesizedLambdaExpression:
|
|
lambdaBody1 = (SyntaxNode?)(object)((AnonymousFunctionExpressionSyntax)(object)node).Body;
|
|
return true;
|
|
case SyntaxKind.FromClause:
|
|
if (node.Parent.IsKind(SyntaxKind.QueryExpression))
|
|
{
|
|
return false;
|
|
}
|
|
lambdaBody1 = (SyntaxNode?)(object)((FromClauseSyntax)(object)node).Expression;
|
|
return true;
|
|
case SyntaxKind.JoinClause:
|
|
{
|
|
JoinClauseSyntax joinClauseSyntax = (JoinClauseSyntax)(object)node;
|
|
lambdaBody1 = (SyntaxNode?)(object)joinClauseSyntax.LeftExpression;
|
|
lambdaBody2 = (SyntaxNode?)(object)joinClauseSyntax.RightExpression;
|
|
return true;
|
|
}
|
|
case SyntaxKind.LetClause:
|
|
lambdaBody1 = (SyntaxNode?)(object)((LetClauseSyntax)(object)node).Expression;
|
|
return true;
|
|
case SyntaxKind.WhereClause:
|
|
lambdaBody1 = (SyntaxNode?)(object)((WhereClauseSyntax)(object)node).Condition;
|
|
return true;
|
|
case SyntaxKind.AscendingOrdering:
|
|
case SyntaxKind.DescendingOrdering:
|
|
lambdaBody1 = (SyntaxNode?)(object)((OrderingSyntax)(object)node).Expression;
|
|
return true;
|
|
case SyntaxKind.SelectClause:
|
|
{
|
|
SelectClauseSyntax selectClauseSyntax = (SelectClauseSyntax)(object)node;
|
|
if (IsReducedSelectOrGroupByClause(selectClauseSyntax, selectClauseSyntax.Expression))
|
|
{
|
|
return false;
|
|
}
|
|
lambdaBody1 = (SyntaxNode?)(object)selectClauseSyntax.Expression;
|
|
return true;
|
|
}
|
|
case SyntaxKind.GroupClause:
|
|
{
|
|
GroupClauseSyntax groupClauseSyntax = (GroupClauseSyntax)(object)node;
|
|
if (IsReducedSelectOrGroupByClause(groupClauseSyntax, groupClauseSyntax.GroupExpression))
|
|
{
|
|
lambdaBody1 = (SyntaxNode?)(object)groupClauseSyntax.ByExpression;
|
|
}
|
|
else
|
|
{
|
|
lambdaBody1 = (SyntaxNode?)(object)groupClauseSyntax.GroupExpression;
|
|
lambdaBody2 = (SyntaxNode?)(object)groupClauseSyntax.ByExpression;
|
|
}
|
|
return true;
|
|
}
|
|
case SyntaxKind.LocalFunctionStatement:
|
|
lambdaBody1 = GetLocalFunctionBody((LocalFunctionStatementSyntax)(object)node);
|
|
return lambdaBody1 != null;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static bool AreEquivalentIgnoringLambdaBodies(SyntaxNode oldNode, SyntaxNode newNode)
|
|
{
|
|
IEnumerable<SyntaxToken> enumerable = oldNode.DescendantTokens((Func<SyntaxNode, bool>)((SyntaxNode node) => node == oldNode || !IsLambdaBodyStatementOrExpression(node)), false);
|
|
IEnumerable<SyntaxToken> enumerable2 = newNode.DescendantTokens((Func<SyntaxNode, bool>)((SyntaxNode node) => node == newNode || !IsLambdaBodyStatementOrExpression(node)), false);
|
|
return EnumerableExtensions.SequenceEqual<SyntaxToken>(enumerable, enumerable2, (Func<SyntaxToken, SyntaxToken, bool>)SyntaxFactory.AreEquivalent);
|
|
}
|
|
|
|
internal static bool IsQueryPairLambda(SyntaxNode syntax)
|
|
{
|
|
if (!syntax.IsKind(SyntaxKind.GroupClause) && !syntax.IsKind(SyntaxKind.JoinClause))
|
|
{
|
|
return syntax.IsKind(SyntaxKind.FromClause);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
internal static bool IsClosureScope(SyntaxNode node)
|
|
{
|
|
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
|
|
switch (node.Kind())
|
|
{
|
|
case SyntaxKind.Block:
|
|
case SyntaxKind.ForStatement:
|
|
case SyntaxKind.ForEachStatement:
|
|
case SyntaxKind.UsingStatement:
|
|
case SyntaxKind.SwitchStatement:
|
|
case SyntaxKind.CatchClause:
|
|
case SyntaxKind.CompilationUnit:
|
|
case SyntaxKind.ConstructorDeclaration:
|
|
case SyntaxKind.ArrowExpressionClause:
|
|
case SyntaxKind.ForEachVariableStatement:
|
|
return true;
|
|
case SyntaxKind.ExpressionStatement:
|
|
case SyntaxKind.GotoCaseStatement:
|
|
case SyntaxKind.ReturnStatement:
|
|
case SyntaxKind.YieldReturnStatement:
|
|
case SyntaxKind.ThrowStatement:
|
|
case SyntaxKind.WhileStatement:
|
|
case SyntaxKind.DoStatement:
|
|
case SyntaxKind.FixedStatement:
|
|
case SyntaxKind.LockStatement:
|
|
case SyntaxKind.IfStatement:
|
|
return true;
|
|
case SyntaxKind.ClassDeclaration:
|
|
case SyntaxKind.StructDeclaration:
|
|
case SyntaxKind.RecordDeclaration:
|
|
case SyntaxKind.RecordStructDeclaration:
|
|
return true;
|
|
case SyntaxKind.AwaitExpression:
|
|
case SyntaxKind.SwitchExpression:
|
|
return true;
|
|
default:
|
|
if (node.Parent != null)
|
|
{
|
|
switch (node.Parent.Kind())
|
|
{
|
|
case SyntaxKind.EqualsValueClause:
|
|
return true;
|
|
case SyntaxKind.ForStatement:
|
|
if ((object)((ForStatementSyntax)(object)node.Parent).Incrementors.FirstOrDefault() == node)
|
|
{
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (IsLambdaBody(node))
|
|
{
|
|
return true;
|
|
}
|
|
if (node is ExpressionSyntax && node.Parent != null && node.Parent.Parent == null)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
internal static int GetDeclaratorPosition(SyntaxNode node)
|
|
{
|
|
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
|
|
if (!(node is SwitchExpressionSyntax { SwitchKeyword: var switchKeyword }))
|
|
{
|
|
return node.SpanStart;
|
|
}
|
|
return ((SyntaxToken)(ref switchKeyword)).SpanStart;
|
|
}
|
|
|
|
private static SyntaxNode? GetLocalFunctionBody(LocalFunctionStatementSyntax localFunctionStatementSyntax)
|
|
{
|
|
object obj = localFunctionStatementSyntax.Body;
|
|
if (obj == null)
|
|
{
|
|
ArrowExpressionClauseSyntax? expressionBody = localFunctionStatementSyntax.ExpressionBody;
|
|
if (expressionBody == null)
|
|
{
|
|
return null;
|
|
}
|
|
obj = expressionBody.Expression;
|
|
}
|
|
return (SyntaxNode?)obj;
|
|
}
|
|
}
|