Skip to content

Commit 9d5c560

Browse files
konzenAdriano Konzen
and
Adriano Konzen
authored
Prioritize property or field over the type / Fix find for static property or field (#357)
* When the type and property have the same name the parser takes the property instead of type * Prioritize property or field over the type / Fix find for static property or field * Update ExpressionParserTests.cs Co-authored-by: Adriano Konzen <[email protected]>
1 parent 5cbde46 commit 9d5c560

File tree

3 files changed

+58
-7
lines changed

3 files changed

+58
-7
lines changed

src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs

+6-4
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,9 @@ Expression ParseIdentifier()
981981
{
982982
_textParser.ValidateToken(TokenId.Identifier);
983983

984-
if (_keywordsHelper.TryGetValue(_textParser.CurrentToken.Text, out object value))
984+
if (_keywordsHelper.TryGetValue(_textParser.CurrentToken.Text, out object value) &&
985+
// Prioritize property or field over the type
986+
!(value is Type && _it != null && FindPropertyOrField(_it.Type, _textParser.CurrentToken.Text, false) != null))
985987
{
986988
Type typeValue = value as Type;
987989
if (typeValue != null)
@@ -1691,7 +1693,7 @@ Expression ParseMemberAccess(Type type, Expression instance)
16911693
return Expression.Dynamic(new DynamicGetMemberBinder(id), type, instance);
16921694
}
16931695
#endif
1694-
if (!_parsingConfig.DisableMemberAccessToIndexAccessorFallback)
1696+
if (!_parsingConfig.DisableMemberAccessToIndexAccessorFallback && instance != null)
16951697
{
16961698
MethodInfo indexerMethod = instance.Type.GetMethod("get_Item", new[] { typeof(string) });
16971699
if (indexerMethod != null)
@@ -2028,14 +2030,14 @@ static MemberInfo FindPropertyOrField(Type type, string memberName, bool staticA
20282030
foreach (Type t in TypeHelper.GetSelfAndBaseTypes(type))
20292031
{
20302032
// Try to find a property with the specified memberName
2031-
MemberInfo member = t.GetTypeInfo().DeclaredProperties.FirstOrDefault(x => x.Name.ToLowerInvariant() == memberName.ToLowerInvariant());
2033+
MemberInfo member = t.GetTypeInfo().DeclaredProperties.FirstOrDefault(x => (!staticAccess || x.GetAccessors(true)[0].IsStatic) && x.Name.ToLowerInvariant() == memberName.ToLowerInvariant());
20322034
if (member != null)
20332035
{
20342036
return member;
20352037
}
20362038

20372039
// If no property is found, try to get a field with the specified memberName
2038-
member = t.GetTypeInfo().DeclaredFields.FirstOrDefault(x => (x.IsStatic || !staticAccess) && x.Name.ToLowerInvariant() == memberName.ToLowerInvariant());
2040+
member = t.GetTypeInfo().DeclaredFields.FirstOrDefault(x => (!staticAccess || x.IsStatic) && x.Name.ToLowerInvariant() == memberName.ToLowerInvariant());
20392041
if (member != null)
20402042
{
20412043
return member;

test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.Linq.Dynamic.Core.Tests.Helpers.Models;
66
using System.Linq.Expressions;
77
using System.Reflection;
8-
using FluentAssertions;
98
using Xunit;
109
using User = System.Linq.Dynamic.Core.Tests.Helpers.Models.User;
1110

test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.cs

+52-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
using System.Linq.Dynamic.Core.Parser;
2-
using System.Linq.Expressions;
1+
using Moq;
32
using NFluent;
3+
using System.Collections.Generic;
4+
using System.Linq.Dynamic.Core.CustomTypeProviders;
5+
using System.Linq.Dynamic.Core.Exceptions;
6+
using System.Linq.Dynamic.Core.Parser;
7+
using System.Linq.Dynamic.Core.Tests.Entities;
8+
using System.Linq.Expressions;
49
using Xunit;
510

611
namespace System.Linq.Dynamic.Core.Tests.Parser
@@ -110,5 +115,50 @@ public void Parse_NullableShouldReturnNullable(string expression, object resultT
110115
Check.That(unaryExpression.Type).Equals(resultType);
111116
Check.That(unaryExpression.ToString()).Equals(result);
112117
}
118+
119+
private readonly ParsingConfig _parsingConfig;
120+
private readonly Mock<IDynamicLinkCustomTypeProvider> _dynamicTypeProviderMock;
121+
122+
public ExpressionParserTests()
123+
{
124+
_dynamicTypeProviderMock = new Mock<IDynamicLinkCustomTypeProvider>();
125+
_dynamicTypeProviderMock.Setup(dt => dt.GetCustomTypes()).Returns(new HashSet<Type>() { typeof(Company), typeof(MainCompany) });
126+
_dynamicTypeProviderMock.Setup(dt => dt.ResolveType(typeof(Company).FullName)).Returns(typeof(Company));
127+
_dynamicTypeProviderMock.Setup(dt => dt.ResolveType(typeof(MainCompany).FullName)).Returns(typeof(MainCompany));
128+
_dynamicTypeProviderMock.Setup(dt => dt.ResolveTypeBySimpleName("Company")).Returns(typeof(Company));
129+
_dynamicTypeProviderMock.Setup(dt => dt.ResolveTypeBySimpleName("MainCompany")).Returns(typeof(MainCompany));
130+
131+
_parsingConfig = new ParsingConfig
132+
{
133+
CustomTypeProvider = _dynamicTypeProviderMock.Object
134+
};
135+
}
136+
137+
[Theory]
138+
[InlineData("it.MainCompany.Name != null", "(company.MainCompany.Name != null)")]
139+
[InlineData("@MainCompany.Companies.Count() > 0", "(company.MainCompany.Companies.Count() > 0)")]
140+
[InlineData("Company.Equals(null, null)", "Equals(null, null)")]
141+
[InlineData("MainCompany.Name", "company.MainCompany.Name")]
142+
[InlineData("Company.Name", "No property or field 'Name' exists in type 'Company'")]
143+
public void Parse_PrioritizePropertyOrFieldOverTheType(string expression, string result)
144+
{
145+
// Arrange
146+
ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(Company), "company") };
147+
var sut = new ExpressionParser(parameters, expression, null, _parsingConfig);
148+
149+
// Act
150+
string parsedExpression = null;
151+
try
152+
{
153+
parsedExpression = sut.Parse(null).ToString();
154+
}
155+
catch (ParseException e)
156+
{
157+
parsedExpression = e.Message;
158+
}
159+
160+
// Assert
161+
Check.That(parsedExpression).Equals(result);
162+
}
113163
}
114164
}

0 commit comments

Comments
 (0)