Stashbox by Peter Csajtai

<PackageReference Include="Stashbox" Version="3.5.0-preview-610" />

 TreeAnalyzer

class TreeAnalyzer
using Stashbox.Utils.Data; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace Stashbox.Expressions.Compile { internal class TreeAnalyzer { private bool isNestedLambda; public ExpandableArray<Expression> CapturedParameters; public ExpandableArray<Expression> DefinedVariables; public ExpandableArray<LambdaExpression, NestedLambda> NestedLambdas; public ExpandableArray<object> Constants; public TreeAnalyzer() { CapturedParameters = new ExpandableArray<Expression>(); DefinedVariables = new ExpandableArray<Expression>(); NestedLambdas = new ExpandableArray<LambdaExpression, NestedLambda>(); Constants = new ExpandableArray<object>(); } public bool Analyze(Expression expression, params ParameterExpression[] parameters) { switch (expression.NodeType) { case ExpressionType.Parameter: if (parameters.ContainsReference(expression) || DefinedVariables.IndexOf(expression) != -1) return true; if (!isNestedLambda) return false; CapturedParameters.AddOrKeep((ParameterExpression)expression); return true; case ExpressionType.Lambda: { LambdaExpression lambdaExpression = (LambdaExpression)expression; TreeAnalyzer treeAnalyzer = Clone(true); if (!treeAnalyzer.Analyze(lambdaExpression.Body, lambdaExpression.Parameters.CastToArray())) return false; NestedLambdas.AddOrKeep(lambdaExpression, new NestedLambda(treeAnalyzer.DefinedVariables, treeAnalyzer.CapturedParameters.Length > 0)); return true; } case ExpressionType.MemberAccess: return Analyze(((MemberExpression)expression).Expression, parameters); case ExpressionType.Constant: { ConstantExpression constantExpression = (ConstantExpression)expression; if (constantExpression.Value == null || Utils.IsInPlaceEmittableConstant(constantExpression.Type, constantExpression.Value)) return true; Constants.AddOrKeep(constantExpression.Value); return true; } case ExpressionType.New: return Analyze(((NewExpression)expression).Arguments, parameters); case ExpressionType.MemberInit: { MemberInitExpression memberInitExpression = (MemberInitExpression)expression; if (Analyze(memberInitExpression.NewExpression, parameters)) return Analyze(memberInitExpression.Bindings, parameters); return false; } case ExpressionType.Block: { BlockExpression blockExpression = (BlockExpression)expression; int count = blockExpression.Variables.Count; for (int i = 0; i < count; i++) { DefinedVariables.AddOrKeep(blockExpression.Variables[i]); } return Analyze(blockExpression.Expressions, parameters); } case ExpressionType.Conditional: { ConditionalExpression conditionalExpression = (ConditionalExpression)expression; if (Analyze(conditionalExpression.Test, parameters) && Analyze(conditionalExpression.IfTrue, parameters)) return Analyze(conditionalExpression.IfFalse, parameters); return false; } case ExpressionType.Default: return true; case ExpressionType.Call: { MethodCallExpression methodCallExpression = (MethodCallExpression)expression; if (methodCallExpression.Object == null || Analyze(methodCallExpression.Object, parameters)) return Analyze(methodCallExpression.Arguments, parameters); return false; } case ExpressionType.Invoke: { InvocationExpression invocationExpression = (InvocationExpression)expression; if (Analyze(invocationExpression.Expression, parameters)) return Analyze(invocationExpression.Arguments, parameters); return false; } case ExpressionType.NewArrayInit: return Analyze(((NewArrayExpression)expression).Expressions, parameters); default: { UnaryExpression unaryExpression = expression as UnaryExpression; if (unaryExpression != null) return Analyze(unaryExpression.Operand, parameters); BinaryExpression binaryExpression = expression as BinaryExpression; if (binaryExpression != null) { if (Analyze(binaryExpression.Left, parameters)) return Analyze(binaryExpression.Right, parameters); return false; } return false; } } } public TreeAnalyzer Clone(bool isLambda = false) { TreeAnalyzer obj = (TreeAnalyzer)MemberwiseClone(); obj.DefinedVariables = new ExpandableArray<Expression>(); obj.isNestedLambda = isLambda; return obj; } private bool Analyze(IList<Expression> expressions, params ParameterExpression[] parameters) { int count = expressions.Count; for (int i = 0; i < count; i++) { if (!Analyze(expressions[i], parameters)) return false; } return true; } private bool Analyze(IList<MemberBinding> bindings, params ParameterExpression[] parameters) { int count = bindings.Count; for (int i = 0; i < count; i++) { MemberBinding memberBinding = bindings[i]; if (memberBinding.BindingType != 0 || !Analyze(((MemberAssignment)memberBinding).Expression, parameters)) return false; } return true; } } }