Skip to content

Commit

Permalink
Add signature support for HoverHandler. (#258)
Browse files Browse the repository at this point in the history
Fixes #259

Signed-off-by: Yaohai Zheng <[email protected]>
  • Loading branch information
yaohaizh authored and fbricon committed Jun 27, 2017
1 parent 687df2b commit 2e6db40
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

import java.io.IOException;
import java.io.Reader;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Stream;

import org.eclipse.core.runtime.CoreException;
Expand All @@ -24,6 +26,8 @@
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.ls.core.internal.hover.JavaElementLabels;
import org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess;
import org.eclipse.lsp4j.MarkedString;
import org.eclipse.lsp4j.jsonrpc.messages.Either;

import com.google.common.io.CharStreams;

Expand All @@ -43,17 +47,24 @@ public class HoverInfoProvider {

private static final long LOCAL_VARIABLE_FLAGS= LABEL_FLAGS & ~JavaElementLabels.F_FULLY_QUALIFIED | JavaElementLabels.F_POST_QUALIFIED;

private static final long COMMON_SIGNATURE_FLAGS = LABEL_FLAGS & ~JavaElementLabels.ALL_FULLY_QUALIFIED
| JavaElementLabels.T_FULLY_QUALIFIED | JavaElementLabels.M_FULLY_QUALIFIED;

private static final String LANGUAGE_ID = "java";

private final ITypeRoot unit;

public HoverInfoProvider(ITypeRoot aUnit) {
this.unit = aUnit;
}

public String computeHover(int line, int column) {
public List<Either<String, MarkedString>> computeHover(int line, int column) {
List<Either<String, MarkedString>> res = new LinkedList<>();
try {
IJavaElement[] elements = JDTUtils.findElementsAtSelection(unit, line, column);
if(elements == null || elements.length == 0) {
return null;
res.add(Either.forLeft(""));
return res;
}
IJavaElement curr = null;
if (elements.length != 1) {
Expand All @@ -68,24 +79,41 @@ public String computeHover(int line, int column) {
.orElse(null);
if (found == null) {
// this would be a binary package fragment
return computeJavadocHover(elements[0]);
curr = elements[0];
}
curr = found;
} else {
curr = elements[0];
}
return computeJavadocHover(curr);
MarkedString signature = this.computeSignature(curr);
if (signature != null) {
res.add(Either.forRight(signature));
}
String javadoc = computeJavadocHover(curr);
if (javadoc != null) {
res.add(Either.forLeft(javadoc));
}

} catch (CoreException e) {
JavaLanguageServerPlugin.logException("Error computing hover", e);
}
return null;
return res;
}

private String computeJavadocHover(IJavaElement element) throws CoreException {
IMember member;
private MarkedString computeSignature(IJavaElement element) {
String elementLabel = null;
if (element instanceof ILocalVariable) {
return JavaElementLabels.getElementLabel(element, LOCAL_VARIABLE_FLAGS);
elementLabel = JavaElementLabels.getElementLabel(element,LOCAL_VARIABLE_FLAGS);
} else {
elementLabel = JavaElementLabels.getElementLabel(element,COMMON_SIGNATURE_FLAGS);
}

return new MarkedString(LANGUAGE_ID, elementLabel);
}


private String computeJavadocHover(IJavaElement element) throws CoreException {
IMember member;
if (element instanceof ITypeParameter) {
member= ((ITypeParameter) element).getDeclaringMember();
} else if (element instanceof IMember) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,34 @@
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal.handlers;

import static org.apache.commons.lang3.StringUtils.defaultString;

import java.util.Arrays;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.ls.core.internal.HoverInfoProvider;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.lsp4j.Hover;
import org.eclipse.lsp4j.MarkedString;
import org.eclipse.lsp4j.TextDocumentPositionParams;
import org.eclipse.lsp4j.jsonrpc.messages.Either;

public class HoverHandler{
public class HoverHandler {

public Hover hover(TextDocumentPositionParams position, IProgressMonitor monitor) {
ITypeRoot unit = JDTUtils.resolveTypeRoot(position.getTextDocument().getUri());

String hover = null;
List<Either<String, MarkedString>> content = null;
if (unit != null && !monitor.isCanceled()) {
hover = computeHover(unit ,position.getPosition().getLine(),
position.getPosition().getCharacter());
content = computeHover(unit, position.getPosition().getLine(), position.getPosition().getCharacter());
}
Hover $ = new Hover();
$.setContents(Arrays.asList(Either.forLeft(defaultString(hover))));
$.setContents(content);
return $;
}

private String computeHover(ITypeRoot unit, int line, int column) {
private List<Either<String, MarkedString>> computeHover(ITypeRoot unit, int line, int column) {
HoverInfoProvider provider = new HoverInfoProvider(unit);
return provider.computeHover(line,column);
return provider.computeHover(line, column);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,16 @@
import java.nio.file.Paths;

import org.eclipse.core.resources.IProject;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.ls.core.internal.ResourceUtils;
import org.eclipse.jdt.ls.core.internal.WorkspaceHelper;
import org.eclipse.jdt.ls.core.internal.managers.AbstractProjectsManagerBasedTest;
import org.eclipse.lsp4j.Hover;
import org.eclipse.lsp4j.MarkedString;
import org.eclipse.lsp4j.TextDocumentPositionParams;
import org.junit.Before;
import org.junit.Test;
Expand Down Expand Up @@ -51,10 +57,14 @@ public class HoverHandlerTest extends AbstractProjectsManagerBasedTest {

private IProject project;

private IPackageFragmentRoot sourceFolder;

@Before
public void setup() throws Exception {
importProjects("eclipse/hello");
project = WorkspaceHelper.getProject("hello");
IJavaProject javaProject = JavaCore.create(project);
sourceFolder = javaProject.getPackageFragmentRoot(javaProject.getProject().getFolder("src"));
handler = new HoverHandler();
}

Expand All @@ -70,25 +80,33 @@ public void testHover() throws Exception {

//then
assertNotNull(hover);
String result = hover.getContents().get(0).getLeft();//wow this is so elegant!
assertEquals("Unexpected hover "+result, "This is foo", result);
assertNotNull(hover.getContents());
MarkedString signature = hover.getContents().get(0).getRight();
assertEquals("Unexpected hover " + signature, "java", signature.getLanguage());
assertEquals("Unexpected hover " + signature, "java.Foo", signature.getValue());
String doc = hover.getContents().get(1).getLeft();
assertEquals("Unexpected hover " + doc, "This is foo", doc);
}

@Test
public void testHoverStandalone() throws Exception {
//given
//Hovers on the System.out
URI standalone = Paths.get("projects","maven","salut","src","main","java","java","Foo.java").toUri();
String payload = createHoverRequest(standalone, 10, 70);
String payload = createHoverRequest(standalone, 10, 71);
TextDocumentPositionParams position = getParams(payload);

//when
Hover hover = handler.hover(position, monitor);

//then
assertNotNull(hover);
String result = hover.getContents().get(0).getLeft();//wow this is so elegant!
assertEquals("Unexpected hover "+result, "This is foo", result);
assertNotNull(hover.getContents());
MarkedString signature = hover.getContents().get(0).getRight();
assertEquals("Unexpected hover " + signature, "java", signature.getLanguage());
assertEquals("Unexpected hover " + signature, "java.Foo", signature.getValue());
String doc = hover.getContents().get(1).getLeft();
assertEquals("Unexpected hover "+doc, "This is foo", doc);
}

@Test
Expand All @@ -106,14 +124,19 @@ public void testEmptyHover() throws Exception {
assertNotNull(hover);
assertNotNull(hover.getContents());
assertEquals(1, hover.getContents().size());
assertEquals("Should find empty hover for "+payload, "", hover.getContents().get(0).getLeft());
assertEquals("Should find empty hover for " + payload, "", hover.getContents().get(0).getLeft());
}

String createHoverRequest(String file, int line, int kar) {
URI uri = project.getFile(file).getRawLocationURI();
return createHoverRequest(uri, line, kar);
}

String createHoverRequest(ICompilationUnit cu, int line, int kar) {
URI uri = cu.getResource().getRawLocationURI();
return createHoverRequest(uri, line, kar);
}

String createHoverRequest(URI file, int line, int kar) {
String fileURI = ResourceUtils.fixURI(file);
return HOVER_TEMPLATE.replace("${file}", fileURI)
Expand All @@ -133,8 +156,43 @@ public void testHoverVariable() throws Exception {

//then
assertNotNull(hover);
String result = hover.getContents().get(0).getLeft();//wow this is so elegant!
assertEquals("Unexpected hover "+result, "String[] args - java.Foo.main(String[])", result);
assertNotNull(hover.getContents());
MarkedString signature = hover.getContents().get(0).getRight();
assertEquals("Unexpected hover " + signature, "java", signature.getLanguage());
assertEquals("Unexpected hover " + signature, "String[] args - java.Foo.main(String[])", signature.getValue());
}

@Test
public void testHoverMethod() throws Exception {
IPackageFragment pack1 = sourceFolder.createPackageFragment("test1", false, null);
StringBuffer buf = new StringBuffer();
buf.append("package test1;\n");
buf.append("import java.util.Vector;\n");
buf.append("public class E {\n");
buf.append(" public int foo(String s) { }\n");
buf.append(" public static void foo2(String s, String s2) { }\n");
buf.append("}\n");
ICompilationUnit cu = pack1.createCompilationUnit("E.java", buf.toString(), false, null);

assertEquals("int test1.E.foo(String s)", getTitleHover(cu, 3, 15));
assertEquals("void test1.E.foo2(String s, String s2)", getTitleHover(cu, 4, 24));
}

@Test
public void testHoverTypeParameters() throws Exception {
IPackageFragment pack1 = sourceFolder.createPackageFragment("test1", false, null);
StringBuffer buf = new StringBuffer();
buf.append("package test1;\n");
buf.append("import java.util.Vector;\n");
buf.append("public class E<T> {\n");
buf.append(" public T foo(T s) { }\n");
buf.append(" public <U> U bar(U s) { }\n");
buf.append("}\n");
ICompilationUnit cu = pack1.createCompilationUnit("E.java", buf.toString(), false, null);

assertEquals("T", getTitleHover(cu, 3, 10));
assertEquals("T test1.E.foo(T s)", getTitleHover(cu, 3, 13));
assertEquals("<U> U test1.E.bar(U s)", getTitleHover(cu, 4, 17));
}

@Test
Expand All @@ -149,7 +207,26 @@ public void testHoverInheritedJavadoc() throws Exception {

// then
assertNotNull(hover);
String result = hover.getContents().get(0).getLeft();//
String result = hover.getContents().get(1).getLeft();//
assertEquals("Unexpected hover ", "This method comes from Foo", result);
}

/**
* @param cu
* @return
*/
private String getTitleHover(ICompilationUnit cu, int line, int character) {
// given
// Hovers on the overriding print()
String payload = createHoverRequest(cu, line, character);
TextDocumentPositionParams position = getParams(payload);

// when
Hover hover = handler.hover(position, monitor);

// then
assertNotNull(hover);
MarkedString result = hover.getContents().get(0).getRight();
return result.getValue();
}
}

0 comments on commit 2e6db40

Please sign in to comment.