Skip to content

Commit

Permalink
jump to definition on break/continue
Browse files Browse the repository at this point in the history
Signed-off-by: Snjezana Peco <[email protected]>
  • Loading branch information
snjeza authored and fbricon committed Nov 22, 2019
1 parent 3c6da12 commit 4100467
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
Expand All @@ -24,6 +25,23 @@
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.BreakStatement;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ContinueStatement;
import org.eclipse.jdt.core.dom.DoStatement;
import org.eclipse.jdt.core.dom.EnhancedForStatement;
import org.eclipse.jdt.core.dom.ForStatement;
import org.eclipse.jdt.core.dom.Initializer;
import org.eclipse.jdt.core.dom.LabeledStatement;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SwitchExpression;
import org.eclipse.jdt.core.dom.SwitchStatement;
import org.eclipse.jdt.core.dom.WhileStatement;
import org.eclipse.jdt.core.manipulation.SharedASTProviderCore;
import org.eclipse.jdt.internal.corext.dom.TokenScanner;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;
Expand Down Expand Up @@ -52,14 +70,83 @@ public List<? extends Location> definition(TextDocumentPositionParams position,
private Location computeDefinitionNavigation(ITypeRoot unit, int line, int column, IProgressMonitor monitor) {
try {
IJavaElement element = JDTUtils.findElementAtSelection(unit, line, column, this.preferenceManager, monitor);
if (element == null) {
return computeBreakContinue(unit, line, column);
}
return computeDefinitionNavigation(element, unit.getJavaProject());
} catch (JavaModelException e) {
} catch (CoreException e) {
JavaLanguageServerPlugin.logException("Problem computing definition for" + unit.getElementName(), e);
}

return null;
}

private Location computeBreakContinue(ITypeRoot typeRoot, int line, int column) throws CoreException {
int offset = JsonRpcHelpers.toOffset(typeRoot.getBuffer(), line, column);
if (offset >= 0) {
CompilationUnit unit = SharedASTProviderCore.getAST(typeRoot, SharedASTProviderCore.WAIT_YES, null);
if (unit == null) {
return null;
}
ASTNode selectedNode = NodeFinder.perform(unit, offset, 0);
ASTNode node = null;
SimpleName label = null;
if (selectedNode instanceof BreakStatement) {
node = selectedNode;
label = ((BreakStatement) node).getLabel();
} else if (selectedNode instanceof ContinueStatement) {
node = selectedNode;
label = ((ContinueStatement) node).getLabel();
} else if (selectedNode instanceof SimpleName && selectedNode.getParent() instanceof BreakStatement) {
node = selectedNode.getParent();
label = ((BreakStatement) node).getLabel();
} else if (selectedNode instanceof SimpleName && selectedNode.getParent() instanceof ContinueStatement) {
node = selectedNode.getParent();
label = ((ContinueStatement) node).getLabel();
}
if (node != null) {
ASTNode parent = node.getParent();
ASTNode target = null;
while (parent != null) {
if (parent instanceof MethodDeclaration || parent instanceof Initializer) {
break;
}
if (label == null) {
if (parent instanceof ForStatement || parent instanceof EnhancedForStatement || parent instanceof WhileStatement || parent instanceof DoStatement) {
target = parent;
break;
}
if (node instanceof BreakStatement) {
if (parent instanceof SwitchStatement || parent instanceof SwitchExpression) {
target = parent;
break;
}
}
if (node instanceof LabeledStatement) {
target = parent;
break;
}
} else if (LabeledStatement.class.isInstance(parent)) {
LabeledStatement ls = (LabeledStatement) parent;
if (ls.getLabel().getIdentifier().equals(label.getIdentifier())) {
target = ls;
break;
}
}
parent = parent.getParent();
}
if (target != null) {
int start = target.getStartPosition();
int end = new TokenScanner(unit.getTypeRoot()).getNextEndOffset(node.getStartPosition(), true) - start;
if (start >= 0 && end >= 0) {
return JDTUtils.toLocation((ICompilationUnit) typeRoot, start, end);
}
}
}
}
return null;
}

public static Location computeDefinitionNavigation(IJavaElement element, IJavaProject javaProject) throws JavaModelException {
if (element == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.sample;

public class TestBreakContinue {

public static void main(String[] args) {
int i = 0;
outer: while (true) {
System.out.println(i);
while (true) {
i++;
if (i == 1) {
continue; // inner
}
if (i == 3) {
continue outer;
}
if (i == 5) {
break; //inner
}
if (i == 7) {
break outer;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,40 @@ public void testJdkClasses() throws Exception {
testClass("org.apache.commons.lang3.stringutils", 6579, 20);
}

@Test
public void testBreakContinue() throws JavaModelException {
String uri = ClassFileUtil.getURI(project, "org.sample.TestBreakContinue");
TextDocumentIdentifier identifier = new TextDocumentIdentifier(uri);
// continue
List<? extends Location> definitions = handler.definition(new TextDocumentPositionParams(identifier, new Position(11, 5)), monitor);
assertNotNull(definitions);
assertEquals(1, definitions.size());
Location definition = definitions.get(0);
assertEquals(8, definition.getRange().getStart().getLine());
assertEquals(3, definition.getRange().getStart().getCharacter());
// outer continue
definitions = handler.definition(new TextDocumentPositionParams(identifier, new Position(14, 5)), monitor);
assertNotNull(definitions);
assertEquals(1, definitions.size());
definition = definitions.get(0);
assertEquals(6, definition.getRange().getStart().getLine());
assertEquals(2, definition.getRange().getStart().getCharacter());
// break
definitions = handler.definition(new TextDocumentPositionParams(identifier, new Position(17, 5)), monitor);
assertNotNull(definitions);
assertEquals(1, definitions.size());
definition = definitions.get(0);
assertEquals(8, definition.getRange().getStart().getLine());
assertEquals(3, definition.getRange().getStart().getCharacter());
// outer break
definitions = handler.definition(new TextDocumentPositionParams(identifier, new Position(20, 5)), monitor);
assertNotNull(definitions);
assertEquals(1, definitions.size());
definition = definitions.get(0);
assertEquals(6, definition.getRange().getStart().getLine());
assertEquals(2, definition.getRange().getStart().getCharacter());
}

private void testClass(String className, int line, int column) throws JavaModelException {
String uri = ClassFileUtil.getURI(project, className);
TextDocumentIdentifier identifier = new TextDocumentIdentifier(uri);
Expand Down

0 comments on commit 4100467

Please sign in to comment.