Skip to content

Commit 4d17b65

Browse files
Add Quick Navigation to Variable's Declaration (#642)
This commit adds context menu in variables view to highlight variable's declaration in the source editor. Fixes : #640
1 parent 7af2360 commit 4d17b65

4 files changed

Lines changed: 173 additions & 0 deletions

File tree

org.eclipse.jdt.debug.ui/plugin.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ openDeclVarType.tooltip=Open the Variable's Declared Type
121121
openDeclVarTypeHierarchy.label=Open Declared Type &Hierarchy
122122
openDeclVarTypeHierarchy.tooltip=Open the Variable's Declared Type Hierarchy
123123

124+
openDeclLocalVarNavigation.label=Navigate to Declaration
125+
openDeclLocalVarNavigation.tooltip=Navigates to variable's declaration
126+
124127
openConcreteVarType.label=Open Act&ual Type
125128
openConcreteVarType.tooltip=Open the Variable's Actual Implementation Type
126129

org.eclipse.jdt.debug.ui/plugin.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,23 @@
747747
enablesFor="1"
748748
id="org.eclipse.jdt.debug.ui.actions.OpenVariableDeclaredType">
749749
</action>
750+
<action
751+
label="%openDeclLocalVarNavigation.label"
752+
helpContextId="open_variable_declared_type_hierarchy_action_context"
753+
tooltip="%openDeclLocalVarNavigation.tooltip"
754+
class="org.eclipse.jdt.internal.debug.ui.actions.NavigateToVarDeclAction"
755+
menubarPath="emptyNavigationGroup"
756+
enablesFor="1"
757+
id="org.eclipse.jdt.debug.ui.actions.OpenDeclLocalVarNavigation">
758+
</action>
759+
<visibility>
760+
<not>
761+
<objectState
762+
name="JavaVariableFilter"
763+
value="isLocalVariableValue">
764+
</objectState>
765+
</not>
766+
</visibility>
750767
</objectContribution>
751768
<objectContribution
752769
objectClass="org.eclipse.jdt.debug.core.IJavaVariable"

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaVarActionFilter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.eclipse.jdt.debug.core.IJavaPrimitiveValue;
2828
import org.eclipse.jdt.debug.core.IJavaType;
2929
import org.eclipse.jdt.debug.core.IJavaVariable;
30+
import org.eclipse.jdt.internal.debug.core.model.JDILocalVariable;
3031
import org.eclipse.jdt.internal.debug.core.model.JDINullValue;
3132
import org.eclipse.jdt.internal.debug.core.model.JDIObjectValue;
3233
import org.eclipse.jdt.internal.debug.core.model.JDIPlaceholderValue;
@@ -207,6 +208,9 @@ else if (value.equals("isValuePrimitive")) { //$NON-NLS-1$
207208
if (value.equals("isFieldVariable")) { //$NON-NLS-1$
208209
return var instanceof IJavaFieldVariable;
209210
}
211+
if (value.equals("isLocalVariableValue")) { //$NON-NLS-1$
212+
return !(var instanceof JDILocalVariable);
213+
}
210214
}
211215
else if (name.equals("ConcreteVariableActionFilter") && value.equals("isConcrete")) { //$NON-NLS-1$ //$NON-NLS-2$
212216
return isDeclaredSameAsConcrete(var);
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 IBM Corporation 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+
* IBM Corporation - initial API and implementation
13+
*******************************************************************************/
14+
15+
package org.eclipse.jdt.internal.debug.ui.actions;
16+
17+
import java.util.List;
18+
import java.util.stream.Collectors;
19+
20+
import org.eclipse.core.resources.IProject;
21+
import org.eclipse.core.resources.ResourcesPlugin;
22+
import org.eclipse.debug.core.model.IStackFrame;
23+
import org.eclipse.debug.internal.ui.DebugUIPlugin;
24+
import org.eclipse.debug.ui.DebugUITools;
25+
import org.eclipse.jdt.core.ICompilationUnit;
26+
import org.eclipse.jdt.core.IJavaProject;
27+
import org.eclipse.jdt.core.IType;
28+
import org.eclipse.jdt.core.JavaCore;
29+
import org.eclipse.jdt.core.dom.AST;
30+
import org.eclipse.jdt.core.dom.ASTParser;
31+
import org.eclipse.jdt.core.dom.ASTVisitor;
32+
import org.eclipse.jdt.core.dom.CompilationUnit;
33+
import org.eclipse.jdt.core.dom.MethodDeclaration;
34+
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
35+
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
36+
import org.eclipse.jdt.debug.core.IJavaStackFrame;
37+
import org.eclipse.jdt.debug.core.IJavaVariable;
38+
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
39+
import org.eclipse.jdt.ui.JavaUI;
40+
import org.eclipse.jface.action.IAction;
41+
import org.eclipse.jface.text.IDocument;
42+
import org.eclipse.jface.text.IRegion;
43+
import org.eclipse.jface.viewers.IStructuredSelection;
44+
import org.eclipse.ui.IEditorPart;
45+
import org.eclipse.ui.texteditor.IDocumentProvider;
46+
import org.eclipse.ui.texteditor.ITextEditor;
47+
48+
public class NavigateToVarDeclAction extends ObjectActionDelegate {
49+
@Override
50+
public void run(IAction action) {
51+
IStructuredSelection selection = getCurrentSelection();
52+
if (selection == null) {
53+
return;
54+
}
55+
try {
56+
if (selection.getFirstElement() instanceof IJavaVariable varE) {
57+
String name = varE.getName();
58+
Object frame = DebugUITools.getDebugContext();
59+
if (frame instanceof IStackFrame jFrame) {
60+
if (jFrame instanceof IJavaStackFrame javaStackFrame) {
61+
String type = javaStackFrame.getLaunch().getLaunchConfiguration().getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String) null);
62+
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(type);
63+
IJavaProject iJavaProject = JavaCore.create(project);
64+
IType iType = iJavaProject.findType(javaStackFrame.getReceivingTypeName());
65+
String currentMethod = javaStackFrame.getMethodName();
66+
List<String> frameParams = javaStackFrame.getArgumentTypeNames();
67+
List<String> ref = frameParams.stream().map(e -> {
68+
int dot = e.lastIndexOf('.');
69+
if (dot >= 0) {
70+
return e.substring(dot + 1);
71+
}
72+
return e;
73+
}).collect(Collectors.toList());
74+
ICompilationUnit cu = iType.getCompilationUnit();
75+
ASTParser parse = ASTParser.newParser(AST.getJLSLatest());
76+
parse.setSource(cu);
77+
parse.setKind(ASTParser.K_COMPILATION_UNIT);
78+
parse.setResolveBindings(true);
79+
CompilationUnit ast = (CompilationUnit) parse.createAST(null);
80+
ast.accept(new ASTVisitor() {
81+
boolean meth = false;
82+
boolean found = false;
83+
@Override
84+
public boolean visit(MethodDeclaration node) {
85+
if (node.getName().getIdentifier().equals(currentMethod)) {
86+
List<Object> parameters = node.parameters();
87+
List<String> methodParams = parameters.stream().map(p -> ((SingleVariableDeclaration) p).getType().toString()).toList();
88+
if (methodParams.equals(ref)) {
89+
meth = true;
90+
for (Object op : node.parameters()) {
91+
SingleVariableDeclaration parm = (SingleVariableDeclaration) op;
92+
if (parm.getName().getIdentifier().equals(name)) {
93+
highlightLine(ast, cu, node.getStartPosition());
94+
found = true;
95+
return false;
96+
}
97+
}
98+
return true;
99+
}
100+
}
101+
return true;
102+
}
103+
104+
@Override
105+
public boolean visit(VariableDeclarationFragment node) {
106+
if (found) {
107+
return false;
108+
}
109+
if (meth && node.getName().getIdentifier().equals(name)) {
110+
found = true;
111+
highlightLine(ast, cu, node.getStartPosition());
112+
return false;
113+
}
114+
return true;
115+
}
116+
});
117+
}
118+
}
119+
}
120+
} catch (Exception e) {
121+
DebugUIPlugin.log(e);
122+
}
123+
}
124+
125+
/**
126+
* This method is responsible for highlighting a line.
127+
*
128+
* @param ast
129+
* Abstract Syntax tree of the code
130+
* @param cu
131+
* compilation unit of the code
132+
* @param startPos
133+
* start position of the code want to highlight
134+
*/
135+
private void highlightLine(CompilationUnit ast, ICompilationUnit cu, int startPos) {
136+
int line = ast.getLineNumber(startPos);
137+
try {
138+
IEditorPart editor = JavaUI.openInEditor(cu);
139+
if (editor instanceof ITextEditor txtEd) {
140+
IDocumentProvider prov = txtEd.getDocumentProvider();
141+
IDocument doc = prov.getDocument(txtEd.getEditorInput());
142+
IRegion lineReg = doc.getLineInformation(line - 1);
143+
txtEd.selectAndReveal(lineReg.getOffset(), lineReg.getLength());
144+
}
145+
} catch (Exception e) {
146+
DebugUIPlugin.log(e);
147+
}
148+
}
149+
}

0 commit comments

Comments
 (0)