Skip to content

Commit 888669a

Browse files
committed
GH-1431: enable index elements to compute document symbols on-demand
1 parent f92a7a5 commit 888669a

File tree

8 files changed

+220
-4
lines changed

8 files changed

+220
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Broadcom
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* https://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Broadcom - initial API and implementation
10+
*******************************************************************************/
11+
package org.springframework.ide.vscode.commons.protocol.spring;
12+
13+
import org.eclipse.lsp4j.DocumentSymbol;
14+
import org.eclipse.lsp4j.Range;
15+
import org.eclipse.lsp4j.WorkspaceSymbol;
16+
17+
public class SimpleSymbolElement extends AbstractSpringIndexElement implements SymbolElement {
18+
19+
private final WorkspaceSymbol symbol;
20+
21+
public SimpleSymbolElement(WorkspaceSymbol symbol) {
22+
this.symbol = symbol;
23+
}
24+
25+
@Override
26+
public DocumentSymbol getDocumentSymbol() {
27+
DocumentSymbol documentSymbol = new DocumentSymbol();
28+
documentSymbol.setName(symbol.getName());
29+
documentSymbol.setKind(symbol.getKind());
30+
documentSymbol.setTags(symbol.getTags());
31+
32+
Range range = symbol.getLocation().isLeft() ? symbol.getLocation().getLeft().getRange() : new Range();
33+
documentSymbol.setRange(range);
34+
documentSymbol.setSelectionRange(range);
35+
36+
return documentSymbol;
37+
}
38+
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Broadcom
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* https://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Broadcom - initial API and implementation
10+
*******************************************************************************/
11+
package org.springframework.ide.vscode.commons.protocol.spring;
12+
13+
import org.eclipse.lsp4j.DocumentSymbol;
14+
15+
public interface SymbolElement {
16+
17+
public DocumentSymbol getDocumentSymbol();
18+
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Broadcom
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* https://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Broadcom - initial API and implementation
10+
*******************************************************************************/
11+
package org.springframework.ide.vscode.boot.index;
12+
13+
import java.util.ArrayList;
14+
import java.util.List;
15+
16+
import org.eclipse.lsp4j.DocumentSymbol;
17+
import org.eclipse.lsp4j.Position;
18+
import org.eclipse.lsp4j.Range;
19+
import org.eclipse.lsp4j.SymbolKind;
20+
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
21+
import org.springframework.ide.vscode.commons.protocol.spring.SymbolElement;
22+
23+
public class SpringIndexToSymbolsConverter {
24+
25+
public static List<DocumentSymbol> createDocumentSymbols(List<SpringIndexElement> indexElements) {
26+
List<DocumentSymbol> result = new ArrayList<>();
27+
28+
for (SpringIndexElement indexElement : indexElements) {
29+
result.add(createSymbol(indexElement));
30+
}
31+
32+
return result;
33+
}
34+
35+
private static DocumentSymbol createSymbol(SpringIndexElement indexElement) {
36+
37+
DocumentSymbol symbol = null;
38+
if (indexElement instanceof SymbolElement symbolElement) {
39+
symbol = symbolElement.getDocumentSymbol();
40+
}
41+
else {
42+
symbol = new DocumentSymbol(indexElement.toString(), SymbolKind.String,
43+
new Range(new Position(), new Position()),
44+
new Range(new Position(), new Position()));
45+
}
46+
47+
List<SpringIndexElement> children = indexElement.getChildren();
48+
if (children != null && children.size() > 0) {
49+
List<DocumentSymbol> childSymbols = new ArrayList<>();
50+
51+
for (SpringIndexElement child : children) {
52+
DocumentSymbol childSymbol = createSymbol(child);
53+
if (childSymbol != null) {
54+
childSymbols.add(childSymbol);
55+
}
56+
}
57+
58+
if (childSymbols.size() > 0) {
59+
symbol.setChildren(childSymbols);
60+
}
61+
}
62+
63+
return symbol;
64+
}
65+
66+
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/RestrictedDefaultSymbolProvider.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
import org.slf4j.Logger;
2323
import org.slf4j.LoggerFactory;
2424
import org.springframework.ide.vscode.boot.java.Annotations;
25+
import org.springframework.ide.vscode.boot.java.beans.CachedBean;
2526
import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider;
27+
import org.springframework.ide.vscode.commons.protocol.spring.SimpleSymbolElement;
2628
import org.springframework.ide.vscode.commons.util.text.TextDocument;
2729

2830
/**
@@ -41,6 +43,7 @@ protected void addSymbolsPass1(Annotation node, ITypeBinding typeBinding,
4143
try {
4244
WorkspaceSymbol symbol = DefaultSymbolProvider.provideDefaultSymbol(node, doc);
4345
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), symbol));
46+
context.getBeans().add(new CachedBean(context.getDocURI(), new SimpleSymbolElement(symbol)));
4447
} catch (Exception e) {
4548
log.warn(e.getMessage());
4649
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringFactoriesIndexer.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@
2828
import java.util.stream.Stream;
2929

3030
import org.apache.commons.codec.digest.DigestUtils;
31+
import org.eclipse.lsp4j.DocumentSymbol;
3132
import org.eclipse.lsp4j.Location;
3233
import org.eclipse.lsp4j.Range;
3334
import org.eclipse.lsp4j.SymbolKind;
3435
import org.eclipse.lsp4j.WorkspaceSymbol;
36+
import org.eclipse.lsp4j.WorkspaceSymbolLocation;
3537
import org.eclipse.lsp4j.jsonrpc.messages.Either;
3638
import org.slf4j.Logger;
3739
import org.slf4j.LoggerFactory;
@@ -100,6 +102,28 @@ public List<WorkspaceSymbol> computeSymbols(IJavaProject project, String docURI,
100102
return computeSymbols(docURI, content);
101103
}
102104

105+
@Override
106+
public List<DocumentSymbol> computeDocumentSymbols(IJavaProject project, String docURI, String content) throws Exception {
107+
return computeSymbols(docURI, content).stream()
108+
.map(workspaceSymbol -> convertToDocumentSymbol(workspaceSymbol))
109+
.toList();
110+
}
111+
112+
private DocumentSymbol convertToDocumentSymbol(WorkspaceSymbol workspaceSymbol) {
113+
Either<Location, WorkspaceSymbolLocation> location = workspaceSymbol.getLocation();
114+
115+
Range range = null;
116+
if (location.isLeft()) {
117+
Location l = location.getLeft();
118+
range = l.getRange();
119+
}
120+
else if (location.isRight()) {
121+
range = new Range();
122+
}
123+
124+
return new DocumentSymbol(workspaceSymbol.getName(), workspaceSymbol.getKind(), range, range);
125+
}
126+
103127
private List<WorkspaceSymbol> computeSymbols(String docURI, String content) {
104128
ImmutableList.Builder<WorkspaceSymbol> symbols = ImmutableList.builder();
105129
PropertiesAst ast = new AntlrParser().parse(content).ast;
@@ -287,5 +311,5 @@ public void removeFiles(IJavaProject project, String[] docURIs) throws Exception
287311
IndexCacheKey key = getCacheKey(project);
288312
cache.removeFiles(key, files, CachedSymbol.class);
289313
}
290-
314+
291315
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import java.util.List;
1414

15+
import org.eclipse.lsp4j.DocumentSymbol;
1516
import org.eclipse.lsp4j.WorkspaceSymbol;
1617
import org.springframework.ide.vscode.commons.java.IJavaProject;
1718

@@ -24,6 +25,7 @@ public interface SpringIndexer {
2425
boolean isInterestedIn(String resource); // note that this might be a document URI or a standard file path on the system
2526

2627
List<WorkspaceSymbol> computeSymbols(IJavaProject project, String docURI, String content) throws Exception;
28+
List<DocumentSymbol> computeDocumentSymbols(IJavaProject project, String docURI, String string) throws Exception;
2729

2830
void initializeProject(IJavaProject project, boolean clean) throws Exception;
2931
void removeProject(IJavaProject project) throws Exception;

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,11 @@
4949
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
5050
import org.eclipse.jdt.core.dom.TypeDeclaration;
5151
import org.eclipse.lsp4j.Diagnostic;
52+
import org.eclipse.lsp4j.DocumentSymbol;
5253
import org.eclipse.lsp4j.WorkspaceSymbol;
5354
import org.slf4j.Logger;
5455
import org.slf4j.LoggerFactory;
56+
import org.springframework.ide.vscode.boot.index.SpringIndexToSymbolsConverter;
5557
import org.springframework.ide.vscode.boot.index.cache.IndexCache;
5658
import org.springframework.ide.vscode.boot.index.cache.IndexCacheKey;
5759
import org.springframework.ide.vscode.boot.java.Annotations;
@@ -71,6 +73,7 @@
7173
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
7274
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
7375
import org.springframework.ide.vscode.commons.protocol.java.Classpath;
76+
import org.springframework.ide.vscode.commons.protocol.spring.SimpleSymbolElement;
7477
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
7578
import org.springframework.ide.vscode.commons.util.UriUtil;
7679
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -366,6 +369,47 @@ public void accept(ReconcileProblem problem) {
366369

367370
return Collections.emptyList();
368371
}
372+
373+
@Override
374+
public List<DocumentSymbol> computeDocumentSymbols(IJavaProject project, String docURI, String content) throws Exception {
375+
if (content != null) {
376+
URI uri = URI.create(docURI);
377+
378+
return cuCache.withCompilationUnit(project, uri, cu -> {
379+
List<CachedSymbol> generatedSymbols = new ArrayList<CachedSymbol>();
380+
List<CachedBean> generatedBeans = new ArrayList<CachedBean>();
381+
382+
IProblemCollector voidProblemCollector = new IProblemCollector() {
383+
@Override
384+
public void endCollecting() {
385+
}
386+
387+
@Override
388+
public void beginCollecting() {
389+
}
390+
391+
@Override
392+
public void accept(ReconcileProblem problem) {
393+
}
394+
};
395+
396+
AtomicReference<TextDocument> docRef = new AtomicReference<>();
397+
String file = UriUtil.toFileString(docURI);
398+
SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, file,
399+
0, docRef, content, generatedSymbols, generatedBeans, voidProblemCollector, SCAN_PASS.ONE, new ArrayList<>(), true);
400+
401+
scanAST(context, false);
402+
403+
List<SpringIndexElement> indexElements = generatedBeans.stream()
404+
.map(cachedBean -> cachedBean.getBean())
405+
.toList();
406+
407+
return SpringIndexToSymbolsConverter.createDocumentSymbols(indexElements);
408+
});
409+
}
410+
411+
return Collections.emptyList();
412+
}
369413

370414
private Set<String> scanFilesInternally(IJavaProject project, DocumentDescriptor[] docs) throws Exception {
371415
final boolean ignoreMethodBodies = false;
@@ -770,6 +814,7 @@ private void extractSymbolInformation(Annotation node, final SpringIndexerJavaCo
770814
WorkspaceSymbol symbol = provideDefaultSymbol(node, context);
771815
if (symbol != null) {
772816
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), symbol));
817+
context.getBeans().add(new CachedBean(context.getDocURI(), new SimpleSymbolElement(symbol)));
773818
}
774819
}
775820

@@ -965,5 +1010,5 @@ private void fileScannedEvent(String file) {
9651010
fileScanListener.fileScanned(file);
9661011
}
9671012
}
968-
1013+
9691014
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@
3131
import org.eclipse.lemminx.dom.DOMDocument;
3232
import org.eclipse.lemminx.dom.DOMNode;
3333
import org.eclipse.lemminx.dom.DOMParser;
34+
import org.eclipse.lsp4j.DocumentSymbol;
3435
import org.eclipse.lsp4j.WorkspaceSymbol;
3536
import org.slf4j.Logger;
3637
import org.slf4j.LoggerFactory;
38+
import org.springframework.ide.vscode.boot.index.SpringIndexToSymbolsConverter;
3739
import org.springframework.ide.vscode.boot.index.cache.IndexCache;
3840
import org.springframework.ide.vscode.boot.index.cache.IndexCacheKey;
3941
import org.springframework.ide.vscode.boot.java.beans.CachedBean;
@@ -352,16 +354,32 @@ private void populateIndex() {
352354
}
353355

354356
@Override
355-
public List<WorkspaceSymbol> computeSymbols(IJavaProject project, String docURI, String content)
356-
throws Exception {
357+
public List<WorkspaceSymbol> computeSymbols(IJavaProject project, String docURI, String content) throws Exception {
357358
if (content != null) {
358359
List<CachedSymbol> generatedSymbols = new ArrayList<>();
359360
List<CachedBean> generatedBeans = new ArrayList<>();
360361

361362
scanFile(project, content, docURI, 0, generatedSymbols, generatedBeans);
362363
return generatedSymbols.stream().map(s -> s.getEnhancedSymbol()).collect(Collectors.toList());
363364
}
365+
366+
return Collections.emptyList();
367+
}
368+
369+
@Override
370+
public List<DocumentSymbol> computeDocumentSymbols(IJavaProject project, String docURI, String content) throws Exception {
371+
if (content != null) {
372+
List<CachedSymbol> generatedSymbols = new ArrayList<>();
373+
List<CachedBean> generatedBeans = new ArrayList<>();
374+
375+
scanFile(project, content, docURI, 0, generatedSymbols, generatedBeans);
376+
377+
return SpringIndexToSymbolsConverter.createDocumentSymbols(generatedBeans.stream().map(cachedBean -> cachedBean.getBean()).toList());
378+
}
379+
364380
return Collections.emptyList();
365381
}
366382

383+
384+
367385
}

0 commit comments

Comments
 (0)