diff --git a/org.eclipse.jdt.debug.tests/java8/Element.java b/org.eclipse.jdt.debug.tests/java8/Element.java new file mode 100644 index 0000000000..ff3978158b --- /dev/null +++ b/org.eclipse.jdt.debug.tests/java8/Element.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2026 IBM Corporation. + * + * 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +public class Element { + + public Element element; + + public Element() { + } + + public Element(Element element) { + this.element = element; + } + + public void iterateElements() { + System.out.println(element); + if (element != null) { + element.iterateElements(); + } + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + public static void main(String[] args) { + Element root = new Element(new SubElement(new Element())); + root.iterateElements(); + } +} \ No newline at end of file diff --git a/org.eclipse.jdt.debug.tests/java8/SubElement.java b/org.eclipse.jdt.debug.tests/java8/SubElement.java new file mode 100644 index 0000000000..8724ae83e2 --- /dev/null +++ b/org.eclipse.jdt.debug.tests/java8/SubElement.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2026 IBM Corporation. + * + * 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +public class SubElement extends Element { + + public SubElement(Element element) { + super(element); + } +} \ 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 45dbe4cef0..a33d412018 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 @@ -556,6 +556,8 @@ synchronized void assert18Project() { cfgs.add(createLaunchConfiguration(jp, "InnerClassBug")); cfgs.add(createLaunchConfiguration(jp, "SuperClass")); cfgs.add(createLaunchConfiguration(jp, "SubClass")); + cfgs.add(createLaunchConfiguration(jp, "Element")); + cfgs.add(createLaunchConfiguration(jp, "SubElement")); loaded18 = true; waitForBuild(); } diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/DebugHoverTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/DebugHoverTests.java index 86ba550361..303abeefbb 100644 --- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/DebugHoverTests.java +++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/DebugHoverTests.java @@ -438,6 +438,7 @@ public void testBug572629_ChainFieldHover_ArrayLengthChainsOnVariableThisExpress removeAllBreakpoints(); } } + public void testBug572629_ChainFieldHover_3Chains_ExpectValueFromChainAtMiddle() throws Exception { sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class)); @@ -1594,4 +1595,42 @@ public void testResolveSameFieldsInSuperAndSub() throws Exception { } } + public void testResolveFieldOnInheritedMethodFrame() throws Exception { + sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class)); + + final String typeName = "Element"; + final String expectedMethod = "iterateElements"; + final int framesNumber = 2; + final int bpLine1 = 26; + + IJavaBreakpoint bp1 = createLineBreakpoint(bpLine1, "", typeName + ".java", typeName); + bp1.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD); + IFile file = (IFile) bp1.getMarker().getResource(); + assertEquals(typeName + ".java", file.getName()); + IJavaThread thread = null; + try { + thread = launchToBreakpoint(typeName); + CompilationUnitEditor part = openEditorAndValidateStack(expectedMethod, framesNumber, file, thread); + JavaDebugHover hover = new JavaDebugHover(); + hover.setEditor(part); + int offset = part.getViewer().getDocument().get().indexOf("element);"); + String variableName = "element"; + IRegion region = new Region(offset, variableName.length()); + String text = selectAndReveal(part, bpLine1, region); + assertEquals(variableName, text); + IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region)); + assertNotNull(info); + String hoverVal = info.getValue().toString(); + assertTrue(hoverVal.contains("SubElement")); + thread = resume(thread); + info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region)); + assertNotNull(info); + hoverVal = info.getValue().toString(); + assertTrue(hoverVal.contains("Element")); + } finally { + terminateAndRemove(thread); + removeAllBreakpoints(); + } + } + } diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugHover.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugHover.java index 6c36a3eeeb..8245fb89e6 100644 --- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugHover.java +++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugHover.java @@ -52,6 +52,7 @@ import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.jdt.core.dom.ThisExpression; import org.eclipse.jdt.core.manipulation.SharedASTProviderCore; +import org.eclipse.jdt.debug.core.IJavaClassType; import org.eclipse.jdt.debug.core.IJavaDebugTarget; import org.eclipse.jdt.debug.core.IJavaObject; import org.eclipse.jdt.debug.core.IJavaReferenceType; @@ -650,7 +651,7 @@ private static Predicate forLocalVariable(ILocalVariable variab private static Predicate forField(IField field) { return frame -> { try { - return frame.getThis() != null && frame.getThis().getJavaType().getName().equals(field.getDeclaringType().getFullyQualifiedName()) + return frame.getThis() != null && isInstanceOfDeclaringType(frame.getThis(), field) && containsVariable(frame, field.getElementName()); } catch (DebugException e) { JDIDebugUIPlugin.log(e); @@ -660,4 +661,16 @@ private static Predicate forField(IField field) { } + private static boolean isInstanceOfDeclaringType(IJavaObject javaObject, IField field) throws DebugException { + String declaringTypeName = field.getDeclaringType().getFullyQualifiedName(); + IJavaType type = javaObject.getJavaType(); + while (type instanceof IJavaClassType classType) { + if (declaringTypeName.equals(classType.getName())) { + return true; + } + type = classType.getSuperclass(); + } + return false; + } + }