Skip to content

Commit 26babf4

Browse files
committed
Expand workspace symbol search to all classes from classpath.
Fixes redhat-developer/vscode-java#204 This fix also includes generating stub class body for source-less classes. Signed-off-by: Fred Bricon <[email protected]>
1 parent ad818cc commit 26babf4

File tree

9 files changed

+392
-98
lines changed

9 files changed

+392
-98
lines changed

org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTUtils.java

Lines changed: 67 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.eclipse.jdt.core.ILocalVariable;
4242
import org.eclipse.jdt.core.IMember;
4343
import org.eclipse.jdt.core.IMemberValuePair;
44+
import org.eclipse.jdt.core.IOpenable;
4445
import org.eclipse.jdt.core.ISourceRange;
4546
import org.eclipse.jdt.core.ISourceReference;
4647
import org.eclipse.jdt.core.ITypeParameter;
@@ -308,20 +309,29 @@ private static ISourceRange getNameRange(IJavaElement element) throws JavaModelE
308309
* @throws JavaModelException
309310
*/
310311
public static Location toLocation(ICompilationUnit unit, int offset, int length) throws JavaModelException {
311-
Location result = new Location();
312-
result.setUri(getFileURI(unit));
313-
int[] loc = JsonRpcHelpers.toLine(unit.getBuffer(), offset);
314-
int[] endLoc = JsonRpcHelpers.toLine(unit.getBuffer(), offset + length);
315-
316-
Range range = new Range();
317-
if (loc != null) {
318-
range.setStart(new Position(loc[0],loc[1]));
319-
}
320-
if (endLoc != null) {
321-
range.setEnd(new Position(endLoc[0],endLoc[1]));
322-
}
323-
result.setRange(range);
324-
return result;
312+
return new Location(getFileURI(unit), toRange(unit, offset, length));
313+
}
314+
315+
/**
316+
* Creates a default location for the class file.
317+
*
318+
* @param classFile
319+
* @return location
320+
* @throws JavaModelException
321+
*/
322+
public static Location toLocation(IClassFile classFile) throws JavaModelException{
323+
return toLocation(classFile, 0, 0);
324+
}
325+
326+
/**
327+
* Creates a default location for the uri.
328+
*
329+
* @param classFile
330+
* @return location
331+
* @throws JavaModelException
332+
*/
333+
public static Location toLocation(String uri) {
334+
return new Location(uri, newRange());
325335
}
326336

327337
/**
@@ -330,55 +340,66 @@ public static Location toLocation(ICompilationUnit unit, int offset, int length)
330340
* @param unit
331341
* @param offset
332342
* @param length
333-
* @return location or null
343+
* @return location
334344
* @throws JavaModelException
335345
*/
336-
public static Location toLocation(IClassFile unit, int offset, int length) throws JavaModelException{
337-
Location result = new Location();
338-
String packageName = unit.getParent().getElementName();
339-
String jarName = unit.getParent().getParent().getElementName();
346+
public static Location toLocation(IClassFile classFile, int offset, int length) throws JavaModelException{
347+
String packageName = classFile.getParent().getElementName();
348+
String jarName = classFile.getParent().getParent().getElementName();
340349
String uriString = null;
341350
try {
342-
uriString = new URI(JDT_SCHEME, "contents", "/" + jarName + "/" + packageName + "/" + unit.getElementName(), unit.getHandleIdentifier(), null).toASCIIString();
351+
uriString = new URI(JDT_SCHEME, "contents", "/" + jarName + "/" + packageName + "/" + classFile.getElementName(), classFile.getHandleIdentifier(), null).toASCIIString();
343352
} catch (URISyntaxException e) {
344353
JavaLanguageServerPlugin.logException("Error generating URI for class ", e);
345354
}
346-
result.setUri(uriString);
347-
IBuffer buffer = unit.getBuffer();
348-
int[] loc = JsonRpcHelpers.toLine(buffer, offset);
349-
int[] endLoc = JsonRpcHelpers.toLine(buffer, offset + length);
350-
351-
Range range = new Range();
352-
if (loc != null) {
353-
range.setStart(new Position(loc[0], loc[1]));
354-
}
355-
if (endLoc != null) {
356-
range.setEnd(new Position(endLoc[0],endLoc[1]));
357-
}
358-
result.setRange(range);
359-
return result;
355+
Range range = toRange(classFile, offset, length);
356+
return new Location(uriString, range);
360357
}
361358

362359
/**
363-
* Creates a range for the given offset and length for a compilation unit
360+
* Creates a range for the given offset and length for an {@link IOpenable}
364361
*
365-
* @param unit
362+
* @param openable
366363
* @param offset
367364
* @param length
368365
* @return
369366
* @throws JavaModelException
370367
*/
371-
public static Range toRange(ICompilationUnit unit, int offset, int length) throws JavaModelException {
372-
Range result = new Range();
373-
final IBuffer buffer = unit.getBuffer();
374-
int[] loc = JsonRpcHelpers.toLine(buffer, offset);
375-
int[] endLoc = JsonRpcHelpers.toLine(buffer, offset + length);
376-
377-
if (loc != null && endLoc != null) {
378-
result.setStart(new Position(loc[0],loc[1]));
379-
result.setEnd(new Position(endLoc[0],endLoc[1]));
368+
public static Range toRange(IOpenable openable, int offset, int length) throws JavaModelException{
369+
Range range = newRange();
370+
if (offset > 0 || length > 0) {
371+
int[] loc = null;
372+
int[] endLoc = null;
373+
IBuffer buffer = openable.getBuffer();
374+
if (buffer != null) {
375+
loc = JsonRpcHelpers.toLine(buffer, offset);
376+
endLoc = JsonRpcHelpers.toLine(buffer, offset + length);
377+
}
378+
if (loc == null) {
379+
loc = new int[2];
380+
}
381+
if (endLoc == null) {
382+
endLoc = new int[2];
383+
}
384+
setPosition(range.getStart(), loc);
385+
setPosition(range.getEnd(), endLoc);
380386
}
381-
return result;
387+
return range;
388+
}
389+
390+
/**
391+
* Creates a new {@link Range} with its start and end {@link Position}s set to line=0, character=0
392+
*
393+
* @return a new {@link Range};
394+
*/
395+
public static Range newRange() {
396+
return new Range(new Position(), new Position());
397+
}
398+
399+
private static void setPosition(Position position, int[] coords) {
400+
assert coords.length == 2;
401+
position.setLine(coords[0]);
402+
position.setCharacter(coords[1]);
382403
}
383404

384405
/**

org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/ClassfileContentHandler.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,56 @@
1515
import org.eclipse.jdt.core.IBuffer;
1616
import org.eclipse.jdt.core.IClassFile;
1717
import org.eclipse.jdt.core.JavaModelException;
18+
import org.eclipse.jdt.core.ToolFactory;
19+
import org.eclipse.jdt.core.util.ClassFileBytesDisassembler;
1820
import org.eclipse.jdt.ls.core.internal.JDTUtils;
1921
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
2022
import org.eclipse.lsp4j.TextDocumentIdentifier;
2123
import org.eclipse.lsp4j.jsonrpc.CompletableFutures;
2224

2325
public class ClassfileContentHandler {
2426

27+
public static final String MISSING_SOURCES_HEADER = " // Failed to get sources. Instead, stub sources have been generated.\n" +
28+
" // Implementation of methods is unavailable.\n";
29+
30+
private static final String LF = "\n";
31+
2532
public CompletableFuture<String> contents(TextDocumentIdentifier param) {
2633
return CompletableFutures.computeAsync(cm->{
34+
String source = null;
2735
try {
2836
IClassFile cf = JDTUtils.resolveClassFile(param.getUri());
2937
if (cf != null) {
3038
IBuffer buffer = cf.getBuffer();
3139
if (buffer != null){
3240
cm.checkCanceled();
3341
JavaLanguageServerPlugin.logInfo("ClassFile contents request completed");
34-
return buffer.getContents();
42+
source = buffer.getContents();
43+
}
44+
if (source == null) {
45+
source = disassemble(cf);
3546
}
3647
}
3748
} catch (JavaModelException e) {
3849
JavaLanguageServerPlugin.logException("Exception getting java element ", e);
3950
}
40-
return null;
51+
if (source == null) {
52+
source = "";//need to return non null value
53+
}
54+
return source;
4155
});
4256
}
4357

58+
private String disassemble(IClassFile classFile) {
59+
ClassFileBytesDisassembler disassembler= ToolFactory.createDefaultClassFileBytesDisassembler();
60+
String disassembledByteCode = null;
61+
try {
62+
disassembledByteCode = disassembler.disassemble(classFile.getBytes(), LF, ClassFileBytesDisassembler.WORKING_COPY);
63+
disassembledByteCode = MISSING_SOURCES_HEADER + LF + disassembledByteCode;
64+
} catch (Exception e) {
65+
JavaLanguageServerPlugin.logError("Unable to disassemble "+ classFile.getHandleIdentifier() );
66+
}
67+
return disassembledByteCode;
68+
}
69+
4470
}

org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JsonRpcHelpers.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ final public class JsonRpcHelpers {
3434
*/
3535
public static int toOffset(IBuffer buffer, int line, int column){
3636
try {
37-
return toDocument(buffer).getLineOffset(line) + column;
37+
if (buffer != null) {
38+
return toDocument(buffer).getLineOffset(line) + column;
39+
}
3840
} catch (BadLocationException e) {
3941
// TODO Auto-generated catch block
4042
e.printStackTrace();
@@ -67,9 +69,12 @@ public static int[] toLine(IBuffer buffer, int offset){
6769
* The returned document may or may not be connected to the buffer.
6870
*
6971
* @param buffer a buffer
70-
* @return a document with the same contents as the buffer
72+
* @return a document with the same contents as the buffer or <code>null</code> is the buffer is <code>null</code>
7173
*/
7274
public static IDocument toDocument(IBuffer buffer) {
75+
if (buffer == null) {
76+
return null;
77+
}
7378
if (buffer instanceof IDocument) {
7479
return (IDocument) buffer;
7580
} else if (buffer instanceof org.eclipse.jdt.ls.core.internal.DocumentAdapter) {

org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceSymbolHandler.java

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import org.eclipse.core.resources.ResourcesPlugin;
1818
import org.eclipse.core.runtime.NullProgressMonitor;
19+
import org.eclipse.jdt.core.Flags;
1920
import org.eclipse.jdt.core.IJavaProject;
2021
import org.eclipse.jdt.core.JavaCore;
2122
import org.eclipse.jdt.core.JavaModelException;
@@ -25,44 +26,67 @@
2526
import org.eclipse.jdt.core.search.SearchPattern;
2627
import org.eclipse.jdt.core.search.TypeNameMatch;
2728
import org.eclipse.jdt.core.search.TypeNameMatchRequestor;
29+
import org.eclipse.jdt.ls.core.internal.JDTUtils;
2830
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
2931
import org.eclipse.lsp4j.Location;
30-
import org.eclipse.lsp4j.Position;
31-
import org.eclipse.lsp4j.Range;
3232
import org.eclipse.lsp4j.SymbolInformation;
33+
import org.eclipse.lsp4j.SymbolKind;
3334

3435
public class WorkspaceSymbolHandler{
3536

36-
List<SymbolInformation> search(String query) {
37+
public List<SymbolInformation> search(String query) {
38+
if (query == null || query.trim().isEmpty()) {
39+
return Collections.emptyList();
40+
}
3741
try {
3842
ArrayList<SymbolInformation> symbols = new ArrayList<>();
39-
4043
new SearchEngine().searchAllTypeNames(null,SearchPattern.R_PATTERN_MATCH, query.toCharArray(), SearchPattern.R_PREFIX_MATCH,IJavaSearchConstants.TYPE, createSearchScope(),new TypeNameMatchRequestor() {
4144

4245
@Override
4346
public void acceptTypeNameMatch(TypeNameMatch match) {
4447
SymbolInformation symbolInformation = new SymbolInformation();
4548
symbolInformation.setContainerName(match.getTypeContainerName());
4649
symbolInformation.setName(match.getSimpleTypeName());
47-
symbolInformation.setKind(DocumentSymbolHandler.mapKind(match.getType()));
48-
Location location = new Location();
49-
location.setUri(match.getType().getResource().getLocationURI().toString());
50-
location.setRange(new Range(new Position(0,0), new Position(0, 0)));
50+
symbolInformation.setKind(mapKind(match));
51+
Location location;
52+
try {
53+
if (match.getType().isBinary()) {
54+
location = JDTUtils.toLocation(match.getType().getClassFile());
55+
} else {
56+
location = JDTUtils.toLocation(match.getType().getResource().getLocationURI().toString());
57+
}
58+
} catch (Exception e) {
59+
JavaLanguageServerPlugin.logException("Unable to determine location for " + match.getSimpleTypeName(), e);
60+
return;
61+
}
5162
symbolInformation.setLocation(location);
5263
symbols.add(symbolInformation);
5364
}
54-
}, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, new NullProgressMonitor());
5565

66+
private SymbolKind mapKind(TypeNameMatch match) {
67+
int flags= match.getModifiers();
68+
if (Flags.isInterface(flags)) {
69+
return SymbolKind.Interface;
70+
}
71+
if (Flags.isAnnotation(flags)) {
72+
return SymbolKind.Property;
73+
}
74+
if (Flags.isEnum(flags)) {
75+
return SymbolKind.Enum;
76+
}
77+
return SymbolKind.Class;
78+
}
79+
}, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, new NullProgressMonitor());
5680
return symbols;
57-
} catch (JavaModelException e) {
81+
} catch (Exception e) {
5882
JavaLanguageServerPlugin.logException("Problem getting search for" + query, e);
5983
}
6084
return Collections.emptyList();
6185
}
6286

6387
private IJavaSearchScope createSearchScope() throws JavaModelException {
6488
IJavaProject[] projects = JavaCore.create(ResourcesPlugin.getWorkspace().getRoot()).getJavaProjects();
65-
return SearchEngine.createJavaSearchScope(projects, IJavaSearchScope.SOURCES);
89+
return SearchEngine.createJavaSearchScope(projects, IJavaSearchScope.SOURCES | IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.SYSTEM_LIBRARIES);
6690
}
6791

6892
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package java;
2+
3+
/**
4+
* This is IFoo
5+
*/
6+
public interface IFoo {
7+
8+
}

0 commit comments

Comments
 (0)