Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add config setting: DisallowNewKeyword #732

Merged
merged 2 commits into from
Sep 10, 2023
Merged
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
7 changes: 6 additions & 1 deletion src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,10 @@ private Expression ParseIdentifier()
return ParseFunctionIsNull();

case KeywordsHelper.FUNCTION_NEW:
if (_parsingConfig.DisallowNewKeyword)
{
throw ParseError(Res.NewOperatorIsNotAllowed);
}
return ParseNew();

case KeywordsHelper.FUNCTION_NULLPROPAGATION:
Expand Down Expand Up @@ -1354,9 +1358,10 @@ private Expression ParseNew()
if (_textParser.CurrentToken.Id == TokenId.Identifier)
{
var newTypeName = _textParser.CurrentToken.Text;

_textParser.NextToken();

while (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus)
while (_textParser.CurrentToken.Id is TokenId.Dot or TokenId.Plus)
{
var sep = _textParser.CurrentToken.Text;
_textParser.NextToken();
Expand Down
13 changes: 10 additions & 3 deletions src/System.Linq.Dynamic.Core/ParsingConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ public class ParsingConfig
/// <summary>
/// Default ParsingConfig
/// </summary>
public static ParsingConfig Default { get; } = new ParsingConfig();
public static ParsingConfig Default { get; } = new();

/// <summary>
/// Default ParsingConfig for EntityFramework Core 2.1 and higher
/// </summary>
public static ParsingConfig DefaultEFCore21 { get; } = new ParsingConfig
public static ParsingConfig DefaultEFCore21 { get; } = new()
{
EvaluateGroupByAtDatabase = true
};
Expand All @@ -30,7 +30,7 @@ public class ParsingConfig
/// <summary>
/// Default ParsingConfig for CosmosDb
/// </summary>
public static ParsingConfig DefaultCosmosDb { get; } = new ParsingConfig
public static ParsingConfig DefaultCosmosDb { get; } = new()
{
RenameEmptyParameterExpressionNames = true
};
Expand Down Expand Up @@ -227,4 +227,11 @@ public IQueryableAnalyzer QueryableAnalyzer
/// Default value is <c>false</c>.
/// </summary>
public bool SupportDotInPropertyNames { get; set; } = false;

/// <summary>
/// Disallows the New() keyword to be used to construct a class.
///
/// Default value is <c>false</c>.
/// </summary>
public bool DisallowNewKeyword { get; set; } = false;
}
1 change: 1 addition & 0 deletions src/System.Linq.Dynamic.Core/Res.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ internal static class Res
public const string MinusCannotBeAppliedToUnsignedInteger = "'-' cannot be applied to unsigned integers.";
public const string MissingAsClause = "Expression is missing an 'as' clause";
public const string NeitherTypeConvertsToOther = "Neither of the types '{0}' and '{1}' converts to the other";
public const string NewOperatorIsNotAllowed = "Using the new operator is not allowed via the ParsingConfig.";
public const string NoApplicableAggregate = "No applicable aggregate method '{0}({1})' exists";
public const string NoApplicableIndexer = "No applicable indexer exists in type '{0}'";
public const string NoApplicableMethod = "No applicable method '{0}' exists in type '{1}'";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Linq.Dynamic.Core.Parser;
using System.Linq.Expressions;
using FluentAssertions;
using FluentAssertions;
using Xunit;

namespace System.Linq.Dynamic.Core.Tests.Parser
Expand All @@ -11,7 +9,7 @@ partial class ExpressionParserTests
public void ParseMemberAccess_DictionaryIndex_On_Dynamic()
{
// Arrange
var products = (new ProductDynamic[0]).AsQueryable();
var products = new ProductDynamic[0].AsQueryable();

// Act
var expression = products.Where("Properties.Name == @0", "First Product").Expression;
Expand All @@ -31,4 +29,4 @@ public class ProductDynamic

public dynamic Properties { get; set; }
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq.Dynamic.Core.Exceptions;
using System.Linq.Dynamic.Core.Parser;
using System.Linq.Expressions;
using FluentAssertions;
Expand Down Expand Up @@ -216,9 +217,10 @@ public void ParseTypeAccess_Via_Constructor_DynamicType_To_String(string newExpr
// Arrange
var parameter = Expression.Parameter(typeof(int));
var parameter2 = Expression.Parameter(typeof(int));
var returnType = DynamicClassFactory.CreateType(new List<DynamicProperty> {
new DynamicProperty("a", typeof(int)),
new DynamicProperty("b", typeof(int))
var returnType = DynamicClassFactory.CreateType(new List<DynamicProperty>
{
new("a", typeof(int)),
new("b", typeof(int))
});

// Act
Expand All @@ -228,4 +230,27 @@ public void ParseTypeAccess_Via_Constructor_DynamicType_To_String(string newExpr
// Assert
expression.ToString().Should().Match(newExpression2);
}

[Fact]
public void Parse_NewOperator_When_DisallowNewKeyword_Is_True_Should_Throw_Exception()
{
// Arrange
var parameter = Expression.Parameter(typeof(int));
var returnType = DynamicClassFactory.CreateType(new List<DynamicProperty>
{
new("a", typeof(int))
});
var config = new ParsingConfig
{
DisallowNewKeyword = true
};

// Act
var parser = new ExpressionParser(new[] { parameter }, "new(1 as a)", new object[] { }, config);

Action action = () => parser.Parse(returnType);

// Assert
action.Should().Throw<ParseException>().Which.Message.Should().Be(Res.NewOperatorIsNotAllowed);
}
}