Skip to content

Commit 530846d

Browse files
gayanperSarikaSinha
authored andcommitted
Bug 575551 - Fix evaluations at deeply nested intermediate lambda frames
The fix will add support to extract variables starting from correct frame in the current call stack for lambda frames. Also this fix generic variables with upper bound type variables. Change-Id: I86a181df34c3a1045c4a30ec07b9dbcd9ab5c073 Signed-off-by: Gayan Perera <[email protected]> Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.debug/+/189357 Tested-by: JDT Bot <[email protected]> Reviewed-by: Sarika Sinha <[email protected]>
1 parent 0a20bdb commit 530846d

File tree

5 files changed

+87
-8
lines changed

5 files changed

+87
-8
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2022 Gayan Perera and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* Gayan Perera - initial API and implementation
13+
*******************************************************************************/
14+
import java.util.List;
15+
import java.util.concurrent.CompletableFuture;
16+
import java.util.concurrent.ExecutionException;
17+
import java.util.stream.Collectors;
18+
import java.util.stream.Stream;
19+
20+
public class Bug575551 {
21+
public void hoverOverLocal(String[] names) throws InterruptedException, ExecutionException {
22+
CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(() -> {
23+
return Stream.of(names).filter(s -> {
24+
try {
25+
return CompletableFuture.supplyAsync(() -> {
26+
return containsDigit(s.codePointAt(0), names.length);
27+
}).get();
28+
} catch (Exception e) {
29+
return false;
30+
}
31+
}).collect(Collectors.toList());
32+
});
33+
future.get();
34+
}
35+
36+
private boolean containsDigit(int c, int length) {
37+
return Bug575551.Character.isDigit(c) && c == length;
38+
}
39+
40+
public static void main(String[] args) throws InterruptedException, ExecutionException {
41+
new Bug575551().hoverOverLocal(new String[] {"name"});
42+
}
43+
44+
public static class Character {
45+
public static boolean isDigit(int c) {
46+
return (new CharacterLatin()).isDigit(c);
47+
}
48+
49+
private static class CharacterLatin {
50+
public boolean isDigit(int ch) {
51+
return ch > 0;
52+
}
53+
}
54+
}
55+
}

org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ synchronized void assert18Project() {
500500
cfgs.add(createLaunchConfiguration(jp, "Bug574395"));
501501
cfgs.add(createLaunchConfiguration(jp, "Bug571310"));
502502
cfgs.add(createLaunchConfiguration(jp, "Bug573547"));
503+
cfgs.add(createLaunchConfiguration(jp, "Bug575551"));
503504
loaded18 = true;
504505
waitForBuild();
505506
}

org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,23 @@ public void testEvaluate_Bug569413_NestedLambdaCapturedParameterAndNull() throws
183183
assertEquals("wrong result : ", "ab", value.getValueString());
184184
}
185185

186+
public void testEvaluate_Bug575551_onIntermediateFrame_InsideLambda_OutFromMethodInvocationFrame() throws Exception {
187+
createMethodBreakpoint("Bug575551$Character$CharacterLatin", "isDigit",
188+
"(I)Z", true, false);
189+
javaThread = launchToBreakpoint("Bug575551");
190+
assertNotNull("The program did not suspend", javaThread);
191+
// at method invocation stack
192+
IValue value = doEval(javaThread, "ch");
193+
assertEquals("wrong result at method stack : ", String.valueOf((int) 'n'), value.getValueString());
194+
195+
// at 1st lambda stack
196+
value = doEval(javaThread, () -> (IJavaStackFrame) javaThread.getStackFrames()[3], "names.length");
197+
assertEquals("wrong result at 1st lambda stack : ", "1", value.getValueString());
198+
199+
value = doEval(javaThread, () -> (IJavaStackFrame) javaThread.getStackFrames()[3], "s");
200+
assertEquals("wrong result at 1st lambda stack : ", "name", value.getValueString());
201+
}
202+
186203
private void debugWithBreakpoint(String testClass, int lineNumber) throws Exception {
187204
createLineBreakpoint(lineNumber, testClass);
188205
javaThread = launchToBreakpoint(testClass);

org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -420,11 +420,11 @@ private String getFixedUnresolvableGenericTypes(IJavaVariable variable) throws D
420420

421421
private void scanAndFixSignature(String genericSignature, String erasureSignature, StringBuilder fixedSignature) {
422422
/*
423-
* This actually fix variables which are type of Generic Types which cannot be resolved to a type in the current content. For example variable
424-
* type like P_OUT in java.util.stream.ReferencePipeline.filter(Predicate<? super P_OUT>)
423+
* This actually fix variables which are type of Generic Types which cannot be resolved to a type in the current context.
424+
* For example variable type like P_OUT in java.util.stream.ReferencePipeline.filter(Predicate<? super P_OUT>)
425425
*
426426
* and also generic signature such as Ljava/util/function/Predicate<+Ljava/util/List<Ljava/lang/Integer;>;>; Ljava/util/Comparator<-TT;>;
427-
* which will fail the properly resolved to the type.
427+
* which will fail to properly resolved to the type.
428428
*/
429429
if (genericSignature.startsWith(String.valueOf(Signature.C_TYPE_VARIABLE)) ||
430430
genericSignature.startsWith(String.valueOf(Signature.C_CAPTURE)) ||
@@ -444,8 +444,11 @@ private void scanAndFixSignature(String genericSignature, String erasureSignatur
444444

445445
String[] typeArguments = Signature.getTypeArguments(genericSignature);
446446
if (typeArguments.length > 0) {
447-
if (typeArguments.length == 1 && typeArguments[0].equals(String.valueOf(Signature.C_STAR))) {
448-
// this is when we have recursive generics, so remove the generics to avoid compilation issues.
447+
if (typeArguments.length == 1 &&
448+
(typeArguments[0].equals(String.valueOf(Signature.C_STAR)) ||
449+
typeArguments[0].startsWith(String.valueOf(new char[] { Signature.C_EXTENDS, Signature.C_TYPE_VARIABLE })))) {
450+
// this is when we have recursive generics or we have a upper bound type variable
451+
// so remove the generics to avoid compilation issues.
449452
return;
450453
}
451454

org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import java.util.Arrays;
1919
import java.util.Collections;
2020
import java.util.List;
21+
import java.util.stream.Collectors;
22+
import java.util.stream.Stream;
2123

2224
import org.eclipse.debug.core.DebugException;
2325
import org.eclipse.debug.core.model.IStackFrame;
@@ -83,9 +85,10 @@ public static List<IVariable> getLambdaFrameVariables(IStackFrame frame) throws
8385
List<IVariable> variables = new ArrayList<>();
8486
if (LambdaUtils.isLambdaFrame(frame)) {
8587
IThread thread = frame.getThread();
86-
IStackFrame[] stackFrames = thread.getStackFrames();
87-
for (int i = 0; i < Math.min(3, stackFrames.length); ++i) {
88-
IStackFrame stackFrame = stackFrames[i];
88+
// look for two frames below the frame which is provided instead starting from first frame.
89+
List<IStackFrame> stackFrames = Stream.of(thread.getStackFrames()).dropWhile(f -> f != frame)
90+
.limit(3).collect(Collectors.toUnmodifiableList());
91+
for (IStackFrame stackFrame : stackFrames) {
8992
IVariable[] stackFrameVariables = stackFrame.getVariables();
9093
variables.addAll(Arrays.asList(stackFrameVariables));
9194
for (IVariable frameVariable : stackFrameVariables) {

0 commit comments

Comments
 (0)