Skip to content

Commit c2fb523

Browse files
committed
More fixes
1 parent 1c93844 commit c2fb523

File tree

5 files changed

+57
-32
lines changed

5 files changed

+57
-32
lines changed

src/Serilog.Expressions/Expressions/Compilation/Is/IsOperatorTransformer.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Serilog.Expressions.Ast;
1+
using Serilog.Events;
2+
using Serilog.Expressions.Ast;
23
using Serilog.Expressions.Compilation.Transformations;
34

45
namespace Serilog.Expressions.Compilation.Is
@@ -12,7 +13,7 @@ public static Expression Rewrite(Expression expression)
1213

1314
protected override Expression Transform(CallExpression lx)
1415
{
15-
if (!Operators.SameOperator(lx.OperatorName.ToLowerInvariant(), Operators.IntermediateOpSqlIs) || lx.Operands.Length != 2)
16+
if (!Operators.SameOperator(lx.OperatorName, Operators.IntermediateOpSqlIs) || lx.Operands.Length != 2)
1617
return base.Transform(lx);
1718

1819
if (lx.Operands[1] is ConstantExpression nul)
@@ -23,8 +24,9 @@ protected override Expression Transform(CallExpression lx)
2324
if (!(lx.Operands[1] is CallExpression not) || not.Operands.Length != 1)
2425
return base.Transform(lx);
2526

26-
nul = not.Operands[0] as ConstantExpression;
27-
if (nul == null || nul.Constant != null)
27+
if (!(not.Operands[0] is ConstantExpression cx) ||
28+
!(cx.Constant is ScalarValue sv) ||
29+
sv.Value != null)
2830
return base.Transform(lx);
2931

3032
return new CallExpression(Operators.RuntimeOpIsNotNull, lx.Operands[0]);

src/Serilog.Expressions/Expressions/Compilation/Linq/LinqExpressionCompiler.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ class LinqExpressionCompiler : SerilogExpressionTransformer<Expression<CompiledE
2424
static readonly ConstructorInfo SequenceValueCtor =
2525
typeof(SequenceValue).GetConstructor(new[] {typeof(IEnumerable<LogEventPropertyValue>)});
2626

27+
static readonly MethodInfo CoerceTrue = typeof(LinqExpressionCompiler).GetMethod(nameof(CoerceToScalarBoolean), BindingFlags.Static | BindingFlags.Public);
28+
29+
public static LogEventPropertyValue CoerceToScalarBoolean(LogEventPropertyValue value)
30+
{
31+
if (value is ScalarValue sv && sv.Value is bool b)
32+
return RuntimeOperators.ScalarBoolean(b);
33+
return RuntimeOperators.ScalarBoolean(false);
34+
}
35+
2736
public static CompiledExpression Compile(Expression expression)
2837
{
2938
if (expression == null) throw new ArgumentNullException(nameof(expression));
@@ -55,7 +64,7 @@ protected override Expression<CompiledExpression> Transform(CallExpression lx)
5564
{
5665
if (shortCircuit)
5766
{
58-
shortCircuitElse = op;
67+
shortCircuitElse = System.Linq.Expressions.Expression.Call(CoerceTrue, op);
5968
break;
6069
}
6170

src/Serilog.Expressions/Expressions/Runtime/RuntimeOperators.cs

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ static class RuntimeOperators
1313
static readonly LogEventPropertyValue ConstantTrue = new ScalarValue(true),
1414
ConstantFalse = new ScalarValue(false);
1515

16-
static LogEventPropertyValue ScalarBoolean(bool value)
16+
internal static LogEventPropertyValue ScalarBoolean(bool value)
1717
{
1818
return value ? ConstantTrue : ConstantFalse;
1919
}
@@ -122,18 +122,21 @@ public static LogEventPropertyValue GreaterThanOrEqual(LogEventPropertyValue lef
122122

123123
public static LogEventPropertyValue Equal(LogEventPropertyValue left, LogEventPropertyValue right)
124124
{
125-
if (Coerce.Numeric(left, out var l) &&
126-
Coerce.Numeric(right, out var r))
127-
return ScalarBoolean(l == r);
125+
// Undefined values propagate through comparisons
126+
if (left == null || right == null)
127+
return null;
128128

129129
return ScalarBoolean(UnboxedEqualHelper(left, right));
130130
}
131131

132132
static bool UnboxedEqualHelper(LogEventPropertyValue left, LogEventPropertyValue right)
133133
{
134-
// "undefined"
135134
if (left == null || right == null)
136-
return false;
135+
throw new ArgumentException("Undefined values should short-circuit.");
136+
137+
if (Coerce.Numeric(left, out var l) &&
138+
Coerce.Numeric(right, out var r))
139+
return l == r;
137140

138141
if (left is ScalarValue sl &&
139142
right is ScalarValue sr)
@@ -144,11 +147,17 @@ static bool UnboxedEqualHelper(LogEventPropertyValue left, LogEventPropertyValue
144147

145148
public static LogEventPropertyValue _Internal_In(LogEventPropertyValue item, LogEventPropertyValue collection)
146149
{
150+
if (item == null)
151+
return null;
152+
147153
if (collection is SequenceValue arr)
148154
{
149155
for (var i = 0; i < arr.Elements.Count; ++i)
150-
if (UnboxedEqualHelper(arr.Elements[i], item))
156+
{
157+
var element = arr.Elements[i];
158+
if (element != null && UnboxedEqualHelper(element, item))
151159
return ConstantTrue;
160+
}
152161

153162
return ConstantFalse;
154163
}
@@ -167,6 +176,9 @@ public static LogEventPropertyValue _Internal_EqualIgnoreCase(LogEventPropertyVa
167176

168177
public static LogEventPropertyValue NotEqual(LogEventPropertyValue left, LogEventPropertyValue right)
169178
{
179+
if (left == null || right == null)
180+
return null;
181+
170182
return ScalarBoolean(!UnboxedEqualHelper(left, right));
171183
}
172184

@@ -184,6 +196,19 @@ public static LogEventPropertyValue Negate(LogEventPropertyValue operand)
184196
return null;
185197
}
186198

199+
public static LogEventPropertyValue Round(LogEventPropertyValue value, LogEventPropertyValue places)
200+
{
201+
if (!Coerce.Numeric(value, out var v) ||
202+
!Coerce.Numeric(places, out var p) ||
203+
p < 0 ||
204+
p > 32) // Check my memory, here :D
205+
{
206+
return null;
207+
}
208+
209+
return new ScalarValue(Math.Round(v, (int)p));
210+
}
211+
187212
public static LogEventPropertyValue Not(LogEventPropertyValue operand)
188213
{
189214
if (operand is null)
@@ -293,8 +318,7 @@ public static LogEventPropertyValue Has(LogEventPropertyValue value)
293318

294319
public static LogEventPropertyValue ElementAt(LogEventPropertyValue items, LogEventPropertyValue index)
295320
{
296-
if (items is SequenceValue arr &&
297-
Coerce.Numeric(index, out var ix))
321+
if (items is SequenceValue arr && Coerce.Numeric(index, out var ix))
298322
{
299323
if (ix != Math.Floor(ix))
300324
return null;
@@ -306,22 +330,20 @@ public static LogEventPropertyValue ElementAt(LogEventPropertyValue items, LogEv
306330
return arr.Elements.ElementAt(idx);
307331
}
308332

309-
if (items is StructureValue st &&
310-
Coerce.String(index, out var s))
333+
if (items is StructureValue st && Coerce.String(index, out var s))
311334
{
312335
if (!LinqExpressionCompiler.TryGetStructurePropertyValue(st, s, out var value))
313336
return null;
314337

315338
return value;
316339
}
317340

318-
if (items is DictionaryValue dict &&
319-
index is ScalarValue sv)
341+
if (items is DictionaryValue dict && index is ScalarValue sv)
320342
{
321-
if (!dict.Elements.TryGetValue(sv, out var value))
322-
return null;
323-
324-
return value;
343+
// The lack of eager numeric type coercion means that here, `sv` may logically equal one
344+
// of the keys, but not be equal according to the dictionary's `IEqualityComparer`.
345+
var entry = dict.Elements.FirstOrDefault(kv => kv.Key != null && UnboxedEqualHelper(kv.Key, sv));
346+
return entry.Value; // KVP is a struct; default is a pair of nulls.
325347
}
326348

327349
return null;

src/Serilog.Expressions/LoggerFilterConfigurationExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using Serilog.Expressions;
44
using Serilog.Expressions.Runtime;
55

6+
// ReSharper disable UnusedMember.Global
7+
68
namespace Serilog
79
{
810
/// <summary>

test/Serilog.Expressions.Tests/ExpressionCompilerTests.cs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -151,15 +151,5 @@ static void AssertEvaluation(string expression, LogEvent match, params LogEvent[
151151
Assert.Single(sink.Events);
152152
Assert.Same(match, sink.Events.Single());
153153
}
154-
155-
[Fact]
156-
public void StructuresAreExposedAsDictionaries()
157-
{
158-
var evt = Some.InformationEvent("{@Person}", new { Name = "nblumhardt" });
159-
var expr = SerilogExpression.Compile("Person");
160-
var val = expr(evt);
161-
var dict = Assert.IsType<Dictionary<string, object>>(val);
162-
Assert.Equal("nblumhardt", dict["Name"]);
163-
}
164154
}
165155
}

0 commit comments

Comments
 (0)