Skip to content

Commit

Permalink
Fix calling methods on a constant string (#804)
Browse files Browse the repository at this point in the history
  • Loading branch information
StefH authored Apr 26, 2024
1 parent 6d0acaa commit a76d856
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 5 deletions.
18 changes: 13 additions & 5 deletions src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1798,8 +1798,9 @@ private Expression ParseMemberAccess(Type? type, Expression? expression, string?
Expression[]? args = null;

var isStaticAccess = expression == null;
var isConstantString = expression is ConstantExpression { Value: string };

if (!isStaticAccess && TypeHelper.TryFindGenericType(typeof(IEnumerable<>), type, out var enumerableType))
if (!isStaticAccess && !isConstantString && TypeHelper.TryFindGenericType(typeof(IEnumerable<>), type, out var enumerableType))
{
var elementType = enumerableType.GetTypeInfo().GetGenericTypeArguments()[0];
if (TryParseEnumerable(expression!, elementType, id, errorPos, type, out args, out var enumerableExpression))
Expand Down Expand Up @@ -2042,25 +2043,32 @@ private Expression ParseAsEnumOrNestedClass(string id)

private bool TryParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type? type, out Expression[]? args, [NotNullWhen(true)] out Expression? expression)
{
// Keep the current _parent.
var oldParent = _parent;

ParameterExpression? outerIt = _it;
ParameterExpression innerIt = ParameterExpressionHelper.CreateParameterExpression(elementType, string.Empty, _parsingConfig.RenameEmptyParameterExpressionNames);

// Set the _parent to the current _it.
_parent = _it;

// Set the outerIt to the current _it.
var outerIt = _it;

// Create a new innerIt based on the elementType.
var innerIt = ParameterExpressionHelper.CreateParameterExpression(elementType, string.Empty, _parsingConfig.RenameEmptyParameterExpressionNames);

if (new[] { "Contains", "ContainsKey", "Skip", "Take" }.Contains(methodName))
{
// for any method that acts on the parent element type, we need to specify the outerIt as scope.
// For any method that acts on the parent element type, we need to specify the outerIt as scope.
_it = outerIt;
}
else
{
// Else we need to specify the innerIt as scope.
_it = innerIt;
}

args = ParseArgumentList();

// Revert the _it and _parent to the old values.
_it = outerIt;
_parent = oldParent;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1651,6 +1651,31 @@ public void DynamicExpressionParser_ParseLambda_StringEquals_WithCombinedConditi
Check.That(result).IsEqualTo(true);
}

// #803
[Fact]
public void DynamicExpressionParser_ParseLambda_StringEquals_WithConstantString()
{
// Arrange
var parameters = new[]
{
Expression.Parameter(typeof(MyClass), "myClass")
};

var invokerArguments = new List<object>
{
new MyClass { Name = "Foo" }
};

// Act
var expression = "Name == \"test\" || \"foo\".Equals(it.Name, StringComparison.OrdinalIgnoreCase)";
var lambdaExpression = DynamicExpressionParser.ParseLambda(parameters, null, expression);
var del = lambdaExpression.Compile();
var result = del.DynamicInvoke(invokerArguments.ToArray());

// Assert
result.Should().Be(true);
}

[Fact]
public void DynamicExpressionParser_ParseLambda_NullPropagation_InstanceMethod_0_Arguments()
{
Expand Down

0 comments on commit a76d856

Please # to comment.