diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index ada4b2b9..32a7bc54 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -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: @@ -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(); diff --git a/src/System.Linq.Dynamic.Core/ParsingConfig.cs b/src/System.Linq.Dynamic.Core/ParsingConfig.cs index 6b574054..157aadd0 100644 --- a/src/System.Linq.Dynamic.Core/ParsingConfig.cs +++ b/src/System.Linq.Dynamic.Core/ParsingConfig.cs @@ -14,12 +14,12 @@ public class ParsingConfig /// /// Default ParsingConfig /// - public static ParsingConfig Default { get; } = new ParsingConfig(); + public static ParsingConfig Default { get; } = new(); /// /// Default ParsingConfig for EntityFramework Core 2.1 and higher /// - public static ParsingConfig DefaultEFCore21 { get; } = new ParsingConfig + public static ParsingConfig DefaultEFCore21 { get; } = new() { EvaluateGroupByAtDatabase = true }; @@ -30,7 +30,7 @@ public class ParsingConfig /// /// Default ParsingConfig for CosmosDb /// - public static ParsingConfig DefaultCosmosDb { get; } = new ParsingConfig + public static ParsingConfig DefaultCosmosDb { get; } = new() { RenameEmptyParameterExpressionNames = true }; @@ -227,4 +227,11 @@ public IQueryableAnalyzer QueryableAnalyzer /// Default value is false. /// public bool SupportDotInPropertyNames { get; set; } = false; + + /// + /// Disallows the New() keyword to be used to construct a class. + /// + /// Default value is false. + /// + public bool DisallowNewKeyword { get; set; } = false; } \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Res.cs b/src/System.Linq.Dynamic.Core/Res.cs index 0b897a85..faaaa21a 100644 --- a/src/System.Linq.Dynamic.Core/Res.cs +++ b/src/System.Linq.Dynamic.Core/Res.cs @@ -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}'"; diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.MemberAccess.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.MemberAccess.cs index a21c9814..8f266e69 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.MemberAccess.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.MemberAccess.cs @@ -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 @@ -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; @@ -31,4 +29,4 @@ public class ProductDynamic public dynamic Properties { get; set; } } -} +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs index 9c92c1b3..45548e49 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs @@ -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; @@ -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 { - new DynamicProperty("a", typeof(int)), - new DynamicProperty("b", typeof(int)) + var returnType = DynamicClassFactory.CreateType(new List + { + new("a", typeof(int)), + new("b", typeof(int)) }); // Act @@ -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 + { + 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().Which.Message.Should().Be(Res.NewOperatorIsNotAllowed); + } } \ No newline at end of file