Răsfoiți Sursa

Debug StepInto stops at beginning of arrow function (#1715)

* Debug step into with arrow function

* Added test
tomatosalat0 1 an în urmă
părinte
comite
5ef97b80ed

+ 72 - 1
Jint.Tests/Runtime/Debugger/StepFlowTests.cs

@@ -1,4 +1,5 @@
-using Esprima.Ast;
+using Esprima;
+using Esprima.Ast;
 using Jint.Runtime.Debugger;
 
 namespace Jint.Tests.Runtime.Debugger
@@ -207,5 +208,75 @@ namespace Jint.Tests.Runtime.Debugger
                 node => Assert.True(node.IsLiteral("dummy"))      // 'dummy';
             );
         }
+
+        [Fact]
+        public void StepIntoNamedFunctionCalls()
+        {
+            var script = @"
+function a( ) { return 2; }
+function b(l) { return l + a(); }
+function c( ) { return b(3) + a(); }
+let res = c();
+";
+
+            var steps = StepIntoScript(script);
+            Assert.Collection(steps,
+                step => Assert.Equal("function c( ) { »return b(3) + a(); }", step),
+                step => Assert.Equal("function b(l) { »return l + a(); }", step),
+                step => Assert.Equal("function a( ) { »return 2; }", step),
+                step => Assert.Equal("function a( ) { return 2; }»", step),
+                step => Assert.Equal("function b(l) { return l + a(); }»", step),
+                step => Assert.Equal("function a( ) { »return 2; }", step),
+                step => Assert.Equal("function a( ) { return 2; }»", step),
+                step => Assert.Equal("function c( ) { return b(3) + a(); }»", step));
+        }
+
+        [Fact]
+        public void StepIntoArrowFunctionCalls()
+        {
+            var script = @"
+const a = ( ) => 2;
+const b = (l) => l + a();
+const c = ( ) => b(3) + a();
+let res = c();
+";
+
+            var steps = StepIntoScript(script);
+            Assert.Collection(steps,
+                step => Assert.Equal("const c = ( ) => »b(3) + a();", step),
+                step => Assert.Equal("const b = (l) => »l + a();", step),
+                step => Assert.Equal("const a = ( ) => »2;", step),
+                step => Assert.Equal("const a = ( ) => 2»;", step),
+                step => Assert.Equal("const b = (l) => l + a()»;", step),
+                step => Assert.Equal("const a = ( ) => »2;", step),
+                step => Assert.Equal("const a = ( ) => 2»;", step),
+                step => Assert.Equal("const c = ( ) => b(3) + a()»;", step));
+        }
+
+        private List<string> StepIntoScript(string script)
+        {
+            var engine = new Engine(options => options
+                .DebugMode()
+                .InitialStepMode(StepMode.Into));
+
+            var stepStatements = new List<string>();
+            var scriptLines = script.Replace("\r\n", "\n").Replace("\r", "\n").Split('\n');
+            engine.DebugHandler.Step += (sender, information) =>
+            {
+                if (information.CurrentNode is not VariableDeclaration && information.CurrentNode is not FunctionDeclaration)
+                    OutputPosition(information.Location);
+                return StepMode.Into;
+            };
+
+            engine.Execute(script);
+            return stepStatements;
+
+            void OutputPosition(Location location)
+            {
+                var line = scriptLines[location.Start.Line - 1];
+                var withPositionIndicator = string.Concat(line.Substring(0, location.Start.Column), "»", line.Substring(location.Start.Column));
+                stepStatements.Add(withPositionIndicator.TrimEnd());
+            }
+        }
     }
 }

+ 1 - 1
Jint/Engine.cs

@@ -506,7 +506,7 @@ namespace Jint
             }
         }
 
-        internal void RunBeforeExecuteStatementChecks(Statement? statement)
+        internal void RunBeforeExecuteStatementChecks(StatementListItem? statement)
         {
             // Avoid allocating the enumerator because we run this loop very often.
             foreach (var constraint in _constraints)

+ 1 - 1
Jint/Runtime/Interpreter/EvaluationContext.cs

@@ -45,7 +45,7 @@ internal sealed class EvaluationContext
     public string? Target;
     public CompletionType Completion;
 
-    public void RunBeforeExecuteStatementChecks(Statement statement)
+    public void RunBeforeExecuteStatementChecks(StatementListItem statement)
     {
         if (_shouldRunBeforeExecuteStatementChecks)
         {

+ 2 - 0
Jint/Runtime/Interpreter/JintFunctionDefinition.cs

@@ -48,6 +48,7 @@ internal sealed class JintFunctionDefinition
                 AsyncFunctionStart(context, promiseCapability, context =>
                 {
                     context.Engine.FunctionDeclarationInstantiation(functionObject, argumentsList);
+                    context.RunBeforeExecuteStatementChecks(Function.Body);
                     var jsValue = _bodyExpression.GetValue(context).Clone();
                     return new Completion(CompletionType.Return, jsValue, _bodyExpression._expression);
                 });
@@ -56,6 +57,7 @@ internal sealed class JintFunctionDefinition
             else
             {
                 argumentsInstance = context.Engine.FunctionDeclarationInstantiation(functionObject, argumentsList);
+                context.RunBeforeExecuteStatementChecks(Function.Body);
                 var jsValue = _bodyExpression.GetValue(context).Clone();
                 result = new Completion(CompletionType.Return, jsValue, Function.Body);
             }