Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGayan Perera2022-01-06 19:05:44 +0000
committerSarika Sinha2022-01-10 19:02:21 +0000
commit530846db516280ca88dbc80e098107ce37501477 (patch)
tree9a81474d605c1b9d9d44574ed2a3498ecc5541a1
parent0a20bdb9a62333eb8cde7b16e801fbb5246da79d (diff)
downloadeclipse.jdt.debug-530846db516280ca88dbc80e098107ce37501477.tar.gz
eclipse.jdt.debug-530846db516280ca88dbc80e098107ce37501477.tar.xz
eclipse.jdt.debug-530846db516280ca88dbc80e098107ce37501477.zip
Bug 575551 - Fix evaluations at deeply nested intermediate lambda framesI20220112-0210I20220111-2130I20220111-1910I20220111-1800I20220111-0450I20220110-1800
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 <gayanper@gmail.com> Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.debug/+/189357 Tested-by: JDT Bot <jdt-bot@eclipse.org> Reviewed-by: Sarika Sinha <sarika.sinha@in.ibm.com>
-rw-r--r--org.eclipse.jdt.debug.tests/java8/Bug575551.java55
-rw-r--r--org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java1
-rw-r--r--org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java17
-rw-r--r--org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java13
-rw-r--r--org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java9
5 files changed, 87 insertions, 8 deletions
diff --git a/org.eclipse.jdt.debug.tests/java8/Bug575551.java b/org.eclipse.jdt.debug.tests/java8/Bug575551.java
new file mode 100644
index 000000000..930b981d6
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/java8/Bug575551.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Gayan Perera and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Gayan Perera - initial API and implementation
+ *******************************************************************************/
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class Bug575551 {
+ public void hoverOverLocal(String[] names) throws InterruptedException, ExecutionException {
+ CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(() -> {
+ return Stream.of(names).filter(s -> {
+ try {
+ return CompletableFuture.supplyAsync(() -> {
+ return containsDigit(s.codePointAt(0), names.length);
+ }).get();
+ } catch (Exception e) {
+ return false;
+ }
+ }).collect(Collectors.toList());
+ });
+ future.get();
+ }
+
+ private boolean containsDigit(int c, int length) {
+ return Bug575551.Character.isDigit(c) && c == length;
+ }
+
+ public static void main(String[] args) throws InterruptedException, ExecutionException {
+ new Bug575551().hoverOverLocal(new String[] {"name"});
+ }
+
+ public static class Character {
+ public static boolean isDigit(int c) {
+ return (new CharacterLatin()).isDigit(c);
+ }
+
+ private static class CharacterLatin {
+ public boolean isDigit(int ch) {
+ return ch > 0;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
index f2fcc6842..599ed29ef 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
@@ -500,6 +500,7 @@ public abstract class AbstractDebugTest extends TestCase implements IEvaluation
cfgs.add(createLaunchConfiguration(jp, "Bug574395"));
cfgs.add(createLaunchConfiguration(jp, "Bug571310"));
cfgs.add(createLaunchConfiguration(jp, "Bug573547"));
+ cfgs.add(createLaunchConfiguration(jp, "Bug575551"));
loaded18 = true;
waitForBuild();
}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java
index 351302a24..39c8b3caa 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java
@@ -183,6 +183,23 @@ public class LambdaVariableTest extends AbstractDebugTest {
assertEquals("wrong result : ", "ab", value.getValueString());
}
+ public void testEvaluate_Bug575551_onIntermediateFrame_InsideLambda_OutFromMethodInvocationFrame() throws Exception {
+ createMethodBreakpoint("Bug575551$Character$CharacterLatin", "isDigit",
+ "(I)Z", true, false);
+ javaThread = launchToBreakpoint("Bug575551");
+ assertNotNull("The program did not suspend", javaThread);
+ // at method invocation stack
+ IValue value = doEval(javaThread, "ch");
+ assertEquals("wrong result at method stack : ", String.valueOf((int) 'n'), value.getValueString());
+
+ // at 1st lambda stack
+ value = doEval(javaThread, () -> (IJavaStackFrame) javaThread.getStackFrames()[3], "names.length");
+ assertEquals("wrong result at 1st lambda stack : ", "1", value.getValueString());
+
+ value = doEval(javaThread, () -> (IJavaStackFrame) javaThread.getStackFrames()[3], "s");
+ assertEquals("wrong result at 1st lambda stack : ", "name", value.getValueString());
+ }
+
private void debugWithBreakpoint(String testClass, int lineNumber) throws Exception {
createLineBreakpoint(lineNumber, testClass);
javaThread = launchToBreakpoint(testClass);
diff --git a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
index 82f5ff9fd..2152c60ca 100644
--- a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
+++ b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
@@ -420,11 +420,11 @@ public class ASTEvaluationEngine implements IAstEvaluationEngine {
private void scanAndFixSignature(String genericSignature, String erasureSignature, StringBuilder fixedSignature) {
/*
- * This actually fix variables which are type of Generic Types which cannot be resolved to a type in the current content. For example variable
- * type like P_OUT in java.util.stream.ReferencePipeline.filter(Predicate<? super P_OUT>)
+ * This actually fix variables which are type of Generic Types which cannot be resolved to a type in the current context.
+ * For example variable type like P_OUT in java.util.stream.ReferencePipeline.filter(Predicate<? super P_OUT>)
*
* and also generic signature such as Ljava/util/function/Predicate<+Ljava/util/List<Ljava/lang/Integer;>;>; Ljava/util/Comparator<-TT;>;
- * which will fail the properly resolved to the type.
+ * which will fail to properly resolved to the type.
*/
if (genericSignature.startsWith(String.valueOf(Signature.C_TYPE_VARIABLE)) ||
genericSignature.startsWith(String.valueOf(Signature.C_CAPTURE)) ||
@@ -444,8 +444,11 @@ public class ASTEvaluationEngine implements IAstEvaluationEngine {
String[] typeArguments = Signature.getTypeArguments(genericSignature);
if (typeArguments.length > 0) {
- if (typeArguments.length == 1 && typeArguments[0].equals(String.valueOf(Signature.C_STAR))) {
- // this is when we have recursive generics, so remove the generics to avoid compilation issues.
+ if (typeArguments.length == 1 &&
+ (typeArguments[0].equals(String.valueOf(Signature.C_STAR)) ||
+ typeArguments[0].startsWith(String.valueOf(new char[] { Signature.C_EXTENDS, Signature.C_TYPE_VARIABLE })))) {
+ // this is when we have recursive generics or we have a upper bound type variable
+ // so remove the generics to avoid compilation issues.
return;
}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java
index ac0c5512b..6cf380392 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java
@@ -18,6 +18,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IStackFrame;
@@ -83,9 +85,10 @@ public class LambdaUtils {
List<IVariable> variables = new ArrayList<>();
if (LambdaUtils.isLambdaFrame(frame)) {
IThread thread = frame.getThread();
- IStackFrame[] stackFrames = thread.getStackFrames();
- for (int i = 0; i < Math.min(3, stackFrames.length); ++i) {
- IStackFrame stackFrame = stackFrames[i];
+ // look for two frames below the frame which is provided instead starting from first frame.
+ List<IStackFrame> stackFrames = Stream.of(thread.getStackFrames()).dropWhile(f -> f != frame)
+ .limit(3).collect(Collectors.toUnmodifiableList());
+ for (IStackFrame stackFrame : stackFrames) {
IVariable[] stackFrameVariables = stackFrame.getVariables();
variables.addAll(Arrays.asList(stackFrameVariables));
for (IVariable frameVariable : stackFrameVariables) {

Back to the top