Skip to content

Commit 05db88a

Browse files
authored
[Dynamic Instrumentation] DEBUG-2560 EL- Fix IsEmpty for string and collections (#5809)
## Summary of changes This PR fix a bug when checking for empty or null string. It also approve the error handling in case of unsupported type. ## Test coverage IsEmpty IsEmptyCollection IsEmptyUnsupportedType
1 parent ceb00d0 commit 05db88a

File tree

8 files changed

+166
-5
lines changed

8 files changed

+166
-5
lines changed

tracer/src/Datadog.Trace/Debugger/Expressions/ProbeExpressionParser.String.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,20 @@ private Expression IsEmpty(JsonTextReader reader, List<ParameterExpression> para
6363

6464
if (source.Type == typeof(string))
6565
{
66-
var emptyMethod = ProbeExpressionParserHelper.GetMethodByReflection(typeof(string), nameof(string.IsNullOrEmpty), Type.EmptyTypes);
67-
return Expression.Call(source, emptyMethod);
66+
var emptyMethod = ProbeExpressionParserHelper.GetMethodByReflection(typeof(string), nameof(string.IsNullOrEmpty), [typeof(string)]);
67+
return Expression.Call(null, emptyMethod, source);
6868
}
6969

70-
// not sure about that, it seems from the RFC that isEmpty should support also collections
71-
var collectionCount = CollectionAndStringLengthExpression(source);
72-
return Expression.Equal(collectionCount, Expression.Constant(0));
70+
try
71+
{
72+
var collectionCount = CollectionAndStringLengthExpression(source);
73+
return Expression.Equal(collectionCount, Expression.Constant(0));
74+
}
75+
catch (InvalidOperationException e)
76+
{
77+
AddError($"{source?.ToString() ?? "N/A"}.IsEmpty", e.Message + ", or a string");
78+
return ReturnDefaultValueExpression();
79+
}
7380
}
7481

7582
private Expression CallStringMethod(JsonTextReader reader, List<ParameterExpression> parameters, ParameterExpression itParameter, MethodInfo method)

tracer/test/Datadog.Trace.Tests/Debugger/DebuggerExpressionLanguageTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ internal struct TestStruct
349349

350350
public Guid? NullableNotNullValue;
351351

352+
public string EmptyString { get; set; }
353+
352354
internal class NestedObject
353355
{
354356
#pragma warning disable SA1401
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Condition:
2+
Json:
3+
{
4+
"isEmpty": [
5+
{
6+
"ref": "EmptyString"
7+
}
8+
]
9+
}
10+
Expression: (
11+
scopeMember,
12+
scopeMember,
13+
scopeMember,
14+
exception,
15+
scopeMemberArray) =>
16+
{
17+
var this = (DebuggerExpressionLanguageTests.TestStruct)scopeMember.Value;
18+
var @return = (string)scopeMember.Value;
19+
var @duration = (TimeSpan)scopeMember.Value;
20+
var @exception = exception;
21+
var IntLocal = (int)scopeMemberArray[0].Value;
22+
var DoubleLocal = (double)scopeMemberArray[1].Value;
23+
var StringLocal = (string)scopeMemberArray[2].Value;
24+
var CollectionLocal = (List<string>)scopeMemberArray[3].Value;
25+
var DictionaryLocal = (Dictionary<string, string>)scopeMemberArray[4].Value;
26+
var NestedObjectLocal = (DebuggerExpressionLanguageTests.TestStruct.NestedObject)scopeMemberArray[5].Value;
27+
var NullLocal = (DebuggerExpressionLanguageTests.TestStruct.NestedObject)scopeMemberArray[6].Value;
28+
var BooleanValue = (bool)scopeMemberArray[7].Value;
29+
var Char = (char)scopeMemberArray[8].Value;
30+
var AnotherChar = (char)scopeMemberArray[9].Value;
31+
var NullableNotNullValueLocal = (Guid?)scopeMemberArray[10].Value;
32+
var NullableNullValueLocal = (Guid?)scopeMemberArray[11].Value;
33+
var IntArg = (int)scopeMemberArray[12].Value;
34+
var DoubleArg = (double)scopeMemberArray[13].Value;
35+
var StringArg = (string)scopeMemberArray[14].Value;
36+
var CollectionArg = (List<string>)scopeMemberArray[15].Value;
37+
var NestedObjectArg = (DebuggerExpressionLanguageTests.TestStruct.NestedObject)scopeMemberArray[16].Value;
38+
var $dd_el_result = string.IsNullOrEmpty(this.EmptyString);
39+
40+
return $dd_el_result;
41+
}
42+
Result: True
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Condition:
2+
Json:
3+
{
4+
"isEmpty": [
5+
{
6+
"ref": "Collection"
7+
}
8+
]
9+
}
10+
Expression: (
11+
scopeMember,
12+
scopeMember,
13+
scopeMember,
14+
exception,
15+
scopeMemberArray) =>
16+
{
17+
var this = (DebuggerExpressionLanguageTests.TestStruct)scopeMember.Value;
18+
var @return = (string)scopeMember.Value;
19+
var @duration = (TimeSpan)scopeMember.Value;
20+
var @exception = exception;
21+
var IntLocal = (int)scopeMemberArray[0].Value;
22+
var DoubleLocal = (double)scopeMemberArray[1].Value;
23+
var StringLocal = (string)scopeMemberArray[2].Value;
24+
var CollectionLocal = (List<string>)scopeMemberArray[3].Value;
25+
var DictionaryLocal = (Dictionary<string, string>)scopeMemberArray[4].Value;
26+
var NestedObjectLocal = (DebuggerExpressionLanguageTests.TestStruct.NestedObject)scopeMemberArray[5].Value;
27+
var NullLocal = (DebuggerExpressionLanguageTests.TestStruct.NestedObject)scopeMemberArray[6].Value;
28+
var BooleanValue = (bool)scopeMemberArray[7].Value;
29+
var Char = (char)scopeMemberArray[8].Value;
30+
var AnotherChar = (char)scopeMemberArray[9].Value;
31+
var NullableNotNullValueLocal = (Guid?)scopeMemberArray[10].Value;
32+
var NullableNullValueLocal = (Guid?)scopeMemberArray[11].Value;
33+
var IntArg = (int)scopeMemberArray[12].Value;
34+
var DoubleArg = (double)scopeMemberArray[13].Value;
35+
var StringArg = (string)scopeMemberArray[14].Value;
36+
var CollectionArg = (List<string>)scopeMemberArray[15].Value;
37+
var NestedObjectArg = (DebuggerExpressionLanguageTests.TestStruct.NestedObject)scopeMemberArray[16].Value;
38+
var $dd_el_result = this.Collection.Count == 0;
39+
40+
return $dd_el_result;
41+
}
42+
Result: False
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
Condition:
2+
Json:
3+
{
4+
"isEmpty": [
5+
{
6+
"ref": "IntNumber"
7+
}
8+
]
9+
}
10+
Expression: (
11+
scopeMember,
12+
scopeMember,
13+
scopeMember,
14+
exception,
15+
scopeMemberArray) =>
16+
{
17+
bool $dd_el_result;
18+
var this = (DebuggerExpressionLanguageTests.TestStruct)scopeMember.Value;
19+
var @return = (string)scopeMember.Value;
20+
var @duration = (TimeSpan)scopeMember.Value;
21+
var @exception = exception;
22+
var IntLocal = (int)scopeMemberArray[0].Value;
23+
var DoubleLocal = (double)scopeMemberArray[1].Value;
24+
var StringLocal = (string)scopeMemberArray[2].Value;
25+
var CollectionLocal = (List<string>)scopeMemberArray[3].Value;
26+
var DictionaryLocal = (Dictionary<string, string>)scopeMemberArray[4].Value;
27+
var NestedObjectLocal = (DebuggerExpressionLanguageTests.TestStruct.NestedObject)scopeMemberArray[5].Value;
28+
var NullLocal = (DebuggerExpressionLanguageTests.TestStruct.NestedObject)scopeMemberArray[6].Value;
29+
var BooleanValue = (bool)scopeMemberArray[7].Value;
30+
var Char = (char)scopeMemberArray[8].Value;
31+
var AnotherChar = (char)scopeMemberArray[9].Value;
32+
var NullableNotNullValueLocal = (Guid?)scopeMemberArray[10].Value;
33+
var NullableNullValueLocal = (Guid?)scopeMemberArray[11].Value;
34+
var IntArg = (int)scopeMemberArray[12].Value;
35+
var DoubleArg = (double)scopeMemberArray[13].Value;
36+
var StringArg = (string)scopeMemberArray[14].Value;
37+
var CollectionArg = (List<string>)scopeMemberArray[15].Value;
38+
var NestedObjectArg = (DebuggerExpressionLanguageTests.TestStruct.NestedObject)scopeMemberArray[16].Value;
39+
40+
return true;
41+
}
42+
Result: True
43+
Errors:
44+
EvaluationError { Expression = this.IntNumber.IsEmpty, Message = Source must be an array or implement ICollection or IReadOnlyCollection, or a string }
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"dsl": "isEmpty(ref EmptyString)",
3+
"isEmpty": [
4+
{
5+
"ref": "EmptyString"
6+
}
7+
]
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"dsl": "isEmpty(ref Collection)",
3+
"isEmpty": [
4+
{
5+
"ref": "Collection"
6+
}
7+
]
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"dsl": "isEmpty(ref IntNumber)",
3+
"isEmpty": [
4+
{
5+
"ref": "IntNumber"
6+
}
7+
]
8+
}

0 commit comments

Comments
 (0)