Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the step-into target on multi line expression. Fix #519 #520

Merged
merged 4 commits into from
Jan 30, 2024

Conversation

gayanper
Copy link
Contributor

@gayanper gayanper commented Nov 25, 2023

The fix try to compare the current line number against the target MethodInvocation start line if the debugger lines doesn't match because the current frame is at a wrapped line even though we are executing the same expression.

@gayanper
Copy link
Contributor Author

@testforstephen Let me know if you see a better condition to use in this scenario.

@testforstephen
Copy link
Contributor

@testforstephen Let me know if you see a better condition to use in this scenario.

I don't get how this fix works. When I tested the snippet you posted in the issue #519, the stepInTargets DAP request returns no results for step-into target operation. Shouldn't we fix MethodInvocationLocator first?

@gayanper
Copy link
Contributor Author

@testforstephen Let me know if you see a better condition to use in this scenario.

I don't get how this fix works. When I tested the snippet you posted in the issue #519, the stepInTargets DAP request returns no results for step-into target operation. Shouldn't we fix MethodInvocationLocator first?

Let me check on this, I see the same, probably I missed to commit something

@gayanper gayanper force-pushed the multiline_statement_stepin branch from 8db3f21 to 9b60b13 Compare December 13, 2023 18:04
@gayanper
Copy link
Contributor Author

@testforstephen Let me know if you see a better condition to use in this scenario.

I don't get how this fix works. When I tested the snippet you posted in the issue #519, the stepInTargets DAP request returns no results for step-into target operation. Shouldn't we fix MethodInvocationLocator first?

Let me check on this, I see the same, probably I missed to commit something

Try now @testforstephen

@@ -71,7 +71,7 @@ public boolean visit(MethodDeclaration node) {

@Override
public boolean visit(TypeDeclaration node) {
return shouldVisitNode(node);
return unit.getRoot() == node.getRoot() || shouldVisitNode(node);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition check unit.getRoot() == node.getRoot() is not needed. I tested #519 snippet without this check, it worked.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason for me it start to fail before in shouldVisitNode the end becomes -1 since the on JDT side the start + length of the node becomes equal to the end of the compilation unit's last position. I will try again without this check.

Copy link
Contributor Author

@gayanper gayanper Dec 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK now I found the reason, if you don't have a empty line at the end of the class, that after the last class definitions' brace, then the end getLineNumber becomes -1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can reproduce it, but i would prefer to modify the implementation shouldVisitNode() to fix the problem.

Since the offset range of the ast node is [node.getStartPosition, node.getStartPosition() + node.getLength() - 1], the ending line should be got from unit.getLineNumber(node.getStartPosition() + node.getLength() - 1).

The fix could be as follow:

    private boolean shouldVisitNode(ASTNode node) {
        int start = unit.getLineNumber(node.getStartPosition());
        int end = unit.getLineNumber(node.getStartPosition() + node.getLength() - 1);

        if (line >= start && line <= end) {
            return true;
        }

        return false;
    }

@@ -438,15 +439,19 @@ private boolean shouldDoExtraStepInto(int originalStackDepth, Location originalL
return true;
}

private boolean isSameLocation(Location original, Location current) {
private boolean isSameLocation(Location original, Location current, MethodInvocation targetStepIn) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look at the caller, actually we took the first parameter as current, the second one as original. So we should change the signature definition to private boolean isSameLocation(Location current, Location original, MethodInvocation targetStepIn).

return originalMethod.equals(currentMethod)
&& original.lineNumber() == current.lineNumber();
&& (original.lineNumber() == current.lineNumber()
|| (targetStepIn != null && targetStepIn.lineStart > current.lineNumber()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last condition check should be (targetStepIn != null && targetStepIn.lineEnd >= current.lineNumber()), which supports multiline expression better.

@testforstephen
Copy link
Contributor

I also found another corner case failure when steping target into List.of("1").

new ArrayList<>(List.of("1"))
      .subList(0, 1)
      .addAll(mergedData());

It looks like the generic method signature (e.g. "(LE;)Ljava/util/List;") we parsed from JDT is slightly different with the one from the JDI (e.g. "(Ljava/lang/Object;)Ljava/util/List;"). We could fix it in another PR.

private boolean isStoppedAtSelectedMethod(StackFrame frame, MethodInvocation selectedMethod) {
Method method = frame.location().method();
if (method != null
&& Objects.equals(method.name(), selectedMethod.methodName)
&& (Objects.equals(method.signature(), selectedMethod.methodSignature)
|| Objects.equals(method.genericSignature(), selectedMethod.methodGenericSignature))) {
ObjectReference thisObject = frame.thisObject();
ReferenceType currentType = (thisObject == null) ? method.declaringType() : thisObject.referenceType();
if ("java.lang.Object".equals(selectedMethod.declaringTypeName)) {
return true;
}
return isSubType(currentType, selectedMethod.declaringTypeName);
}
return false;

@gayanper gayanper force-pushed the multiline_statement_stepin branch from 9b60b13 to 8ec67a0 Compare December 16, 2023 11:30
@@ -71,7 +71,7 @@ public boolean visit(MethodDeclaration node) {

@Override
public boolean visit(TypeDeclaration node) {
return shouldVisitNode(node);
return unit.getRoot() == node.getRoot() || shouldVisitNode(node);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can reproduce it, but i would prefer to modify the implementation shouldVisitNode() to fix the problem.

Since the offset range of the ast node is [node.getStartPosition, node.getStartPosition() + node.getLength() - 1], the ending line should be got from unit.getLineNumber(node.getStartPosition() + node.getLength() - 1).

The fix could be as follow:

    private boolean shouldVisitNode(ASTNode node) {
        int start = unit.getLineNumber(node.getStartPosition());
        int end = unit.getLineNumber(node.getStartPosition() + node.getLength() - 1);

        if (line >= start && line <= end) {
            return true;
        }

        return false;
    }

return originalMethod.equals(currentMethod)
&& original.lineNumber() == current.lineNumber();
&& (original.lineNumber() == current.lineNumber()
|| (targetStepIn != null && targetStepIn.lineStart >= current.lineNumber()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't work for multiline method invocation. We should use targetStepIn.lineEnd in the last check, e.g. targetStepIn.lineEnd >= current.lineNumber().

For the use case below, step-into target filterMe doesn't work, it stops at the line of "2", "3", .

new ArrayList<>(List.of("1"))
        .subList(0, 1)
        .addAll(filterMe("1", 
            "2", "3", 
            "4"));

Copy link
Contributor

@testforstephen testforstephen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the PR to fix the comments. Now it's good to merge.

@testforstephen testforstephen merged commit 431de23 into microsoft:main Jan 30, 2024
6 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants