Skip to content

Commit 0063608

Browse files
committed
Data query parameter go to definition, doc highlights and inlay hints
1 parent 42eca4f commit 0063608

34 files changed

+1056
-280
lines changed

headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/composable/CompositeLanguageServerComponents.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import org.eclipse.lsp4j.Hover;
3232
import org.eclipse.lsp4j.HoverParams;
3333
import org.eclipse.lsp4j.InlayHint;
34-
import org.eclipse.lsp4j.InlayHintParams;
3534
import org.eclipse.lsp4j.Range;
3635
import org.eclipse.lsp4j.SemanticTokensLegend;
3736
import org.eclipse.lsp4j.SemanticTokensWithRegistrationOptions;
@@ -175,15 +174,14 @@ public List<? extends CodeLens> handle(CancelChecker cancelToken, CodeLensParams
175174
this.inlayHintHandler = new InlayHintHandler() {
176175

177176
@Override
178-
public List<InlayHint> handle(CancelChecker token, InlayHintParams params) {
179-
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(params.getTextDocument().getUri());
177+
public List<InlayHint> handle(TextDocument doc, Range r, CancelChecker token) {
180178
LanguageId language = doc.getLanguageId();
181179
List<LanguageServerComponents> subComponents = componentsByLanguageId.get(language);
182180
if (subComponents != null) {
183181
return subComponents.stream()
184182
.map(sc -> sc.getInlayHintHandler())
185183
.filter(h -> h.isPresent())
186-
.flatMap(h -> h.get().handle(token, params).stream())
184+
.flatMap(h -> h.get().handle(doc, r, token).stream())
187185
.collect(Collectors.toList());
188186
}
189187
// No applicable subEngine...

headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/semantic/tokens/SemanticTokenData.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@
1313
import java.util.Arrays;
1414
import java.util.Objects;
1515

16-
public record SemanticTokenData(int start, int end, String type, String[] modifiers) implements Comparable<SemanticTokenData>{
16+
public record SemanticTokenData(
17+
int start,
18+
int end,
19+
String type,
20+
String[] modifiers
21+
) implements Comparable<SemanticTokenData> {
1722

1823
@Override
1924
public int compareTo(SemanticTokenData o) {

headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/InlayHintHandler.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
import java.util.List;
1414

1515
import org.eclipse.lsp4j.InlayHint;
16-
import org.eclipse.lsp4j.InlayHintParams;
16+
import org.eclipse.lsp4j.Range;
1717
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
18+
import org.springframework.ide.vscode.commons.util.text.TextDocument;
1819

1920
public interface InlayHintHandler {
2021

21-
List<InlayHint> handle(CancelChecker token, InlayHintParams params);
22+
List<InlayHint> handle(TextDocument doc, Range range, CancelChecker cancelChecker);
2223

2324
}

headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -581,9 +581,12 @@ public CompletableFuture<List<InlayHint>> inlayHint(InlayHintParams params) {
581581
InlayHintHandler handler = this.inlayHintHandler;
582582

583583
if (handler != null) {
584-
return CompletableFutures.computeAsync(messageWorkerThreadPool, cancelToken -> {
585-
return handler.handle(cancelToken, params);
586-
});
584+
TextDocument doc = getLatestSnapshot(params.getTextDocument().getUri());
585+
if (doc != null) {
586+
return CompletableFutures.computeAsync(messageWorkerThreadPool, cancelToken -> {
587+
return handler.handle(doc, params.getRange(), cancelToken);
588+
});
589+
}
587590
}
588591
return CompletableFuture.completedFuture(Collections.emptyList());
589592
}

headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java

+10
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.eclipse.lsp4j.CompletionList;
4242
import org.eclipse.lsp4j.DefinitionParams;
4343
import org.eclipse.lsp4j.Diagnostic;
44+
import org.eclipse.lsp4j.DocumentHighlight;
4445
import org.eclipse.lsp4j.DocumentSymbol;
4546
import org.eclipse.lsp4j.Hover;
4647
import org.eclipse.lsp4j.InsertReplaceEdit;
@@ -240,6 +241,15 @@ public List<Range> assertHighlights(String... expectedHighlights) throws Excepti
240241
assertEquals(ImmutableList.copyOf(expectedHighlights), actualHighlights);
241242
return ranges;
242243
}
244+
245+
public void assertDocumentHighlights(String afterString, DocumentHighlight... expected) throws Exception {
246+
int pos = getRawText().indexOf(afterString);
247+
if (pos>=0) {
248+
pos += afterString.length();
249+
}
250+
List<? extends DocumentHighlight> actual = harness.getDocumentHighlights(doc.getId(), doc.toPosition(pos));
251+
assertEquals(ImmutableList.copyOf(expected), actual);
252+
}
243253

244254
/**
245255
* Get the editor text, with cursor markers inserted (for easy textual comparison

headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java

+6
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.util.Random;
3636
import java.util.Set;
3737
import java.util.concurrent.CompletableFuture;
38+
import java.util.concurrent.ExecutionException;
3839
import java.util.concurrent.Future;
3940
import java.util.function.Function;
4041
import java.util.stream.Collectors;
@@ -65,6 +66,8 @@
6566
import org.eclipse.lsp4j.DidChangeWatchedFilesParams;
6667
import org.eclipse.lsp4j.DidCloseTextDocumentParams;
6768
import org.eclipse.lsp4j.DidOpenTextDocumentParams;
69+
import org.eclipse.lsp4j.DocumentHighlight;
70+
import org.eclipse.lsp4j.DocumentHighlightParams;
6871
import org.eclipse.lsp4j.DocumentSymbol;
6972
import org.eclipse.lsp4j.DocumentSymbolCapabilities;
7073
import org.eclipse.lsp4j.DocumentSymbolParams;
@@ -679,6 +682,9 @@ public List<? extends CodeLens> getCodeLenses(TextDocumentInfo document) throws
679682
return getServer().getTextDocumentService().codeLens(params).get();
680683
}
681684

685+
public List<? extends DocumentHighlight> getDocumentHighlights(TextDocumentIdentifier docId, Position cursor) throws InterruptedException, ExecutionException {
686+
return getServer().getTextDocumentService().documentHighlight(new DocumentHighlightParams(docId, cursor)).get();
687+
}
682688

683689
public CompletionItem resolveCompletionItem(CompletionItem maybeUnresolved) {
684690
if (getServer().hasLazyCompletionResolver()) {

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
import org.springframework.ide.vscode.boot.java.beans.DependsOnDefinitionProvider;
4949
import org.springframework.ide.vscode.boot.java.beans.QualifierDefinitionProvider;
5050
import org.springframework.ide.vscode.boot.java.beans.ResourceDefinitionProvider;
51+
import org.springframework.ide.vscode.boot.java.data.jpa.queries.DataQueryParameterDefinitionProvider;
52+
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtDataQuerySemanticTokensProvider;
5153
import org.springframework.ide.vscode.boot.java.handlers.BootJavaCodeActionProvider;
5254
import org.springframework.ide.vscode.boot.java.handlers.BootJavaReconcileEngine;
5355
import org.springframework.ide.vscode.boot.java.handlers.JavaCodeActionHandler;
@@ -394,12 +396,13 @@ BootJavaCodeActionProvider getBootJavaCodeActionProvider(JavaProjectFinder proje
394396
}
395397

396398
@Bean
397-
JavaDefinitionHandler javaDefinitionHandler(CompilationUnitCache cuCache, JavaProjectFinder projectFinder, SpringMetamodelIndex springIndex) {
399+
JavaDefinitionHandler javaDefinitionHandler(SimpleLanguageServer server, CompilationUnitCache cuCache, JavaProjectFinder projectFinder, SpringMetamodelIndex springIndex, JdtDataQuerySemanticTokensProvider qurySemanticTokens) {
398400
return new JavaDefinitionHandler(cuCache, projectFinder, List.of(
399401
new ValueDefinitionProvider(),
400402
new DependsOnDefinitionProvider(springIndex),
401403
new ResourceDefinitionProvider(springIndex),
402-
new QualifierDefinitionProvider(springIndex)));
404+
new QualifierDefinitionProvider(springIndex),
405+
new DataQueryParameterDefinitionProvider(server.getTextDocumentService(), qurySemanticTokens)));
403406
}
404407

405408
@Bean

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

+10
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
import org.springframework.ide.vscode.boot.java.cron.JdtCronReconciler;
2121
import org.springframework.ide.vscode.boot.java.cron.JdtCronSemanticTokensProvider;
2222
import org.springframework.ide.vscode.boot.java.data.jpa.queries.HqlSemanticTokens;
23+
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtDataQueriesInlayHintsProvider;
2324
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtDataQuerySemanticTokensProvider;
25+
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryDocHighlightsProvider;
2426
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JpqlSemanticTokens;
2527
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JpqlSupportState;
2628
import org.springframework.ide.vscode.boot.java.data.jpa.queries.QueryJdtAstReconciler;
@@ -130,6 +132,14 @@ public class JdtConfig {
130132
return new JdtDataQuerySemanticTokensProvider(jpqlProvider, hqlProvider, supportState, spelSemanticTokens);
131133
}
132134

135+
@Bean JdtDataQueriesInlayHintsProvider jdtDataQueriesInlayHintsProvider(JdtDataQuerySemanticTokensProvider semanticTokensProvider) {
136+
return new JdtDataQueriesInlayHintsProvider(semanticTokensProvider);
137+
}
138+
139+
@Bean JdtQueryDocHighlightsProvider jdtDocHighlightsProvider(JdtDataQuerySemanticTokensProvider semanticTokensProvider) {
140+
return new JdtQueryDocHighlightsProvider(semanticTokensProvider);
141+
}
142+
133143
@Bean JdtCronSemanticTokensProvider jdtCronSemanticTokensProvider(CronSemanticTokens cronProvider) {
134144
return new JdtCronSemanticTokensProvider(cronProvider);
135145
}

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

+20-3
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import org.springframework.ide.vscode.commons.languageserver.util.DocumentHighlightHandler;
7272
import org.springframework.ide.vscode.commons.languageserver.util.DocumentSymbolHandler;
7373
import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler;
74+
import org.springframework.ide.vscode.commons.languageserver.util.InlayHintHandler;
7475
import org.springframework.ide.vscode.commons.languageserver.util.ReferencesHandler;
7576
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
7677
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
@@ -116,6 +117,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
116117
private BootJavaCodeActionProvider codeActionProvider;
117118
private DocumentSymbolHandler docSymbolProvider;
118119
private JdtSemanticTokensHandler semanticTokensHandler;
120+
private JdtInlayHintsHandler inlayHintsHandler;
119121

120122
public BootJavaLanguageServerComponents(ApplicationContext appContext) {
121123
this.server = appContext.getBean(SimpleLanguageServer.class);
@@ -176,14 +178,19 @@ public BootJavaLanguageServerComponents(ApplicationContext appContext) {
176178

177179
codeLensHandler = createCodeLensEngine(springSymbolIndex, projectFinder, server);
178180

179-
highlightsEngine = createDocumentHighlightEngine(springSymbolIndex);
181+
highlightsEngine = createDocumentHighlightEngine(appContext);
180182
documents.onDocumentHighlight(highlightsEngine);
181183

182184
Map<String, JdtSemanticTokensProvider> jdtSemanticTokensProviders = appContext.getBeansOfType(JdtSemanticTokensProvider.class);
183185
if (!jdtSemanticTokensProviders.isEmpty()) {
184186
semanticTokensHandler = new JdtSemanticTokensHandler(cuCache, projectFinder, jdtSemanticTokensProviders.values());
185187
}
186188

189+
Map<String, JdtInlayHintsProvider> jdtInlayHintsProviders = appContext.getBeansOfType(JdtInlayHintsProvider.class);
190+
if (!jdtSemanticTokensProviders.isEmpty()) {
191+
inlayHintsHandler = new JdtInlayHintsHandler(cuCache, projectFinder, jdtInlayHintsProviders.values());
192+
}
193+
187194
config.addListener(ignore -> {
188195
log.info("update live process tracker settings - start");
189196

@@ -313,9 +320,14 @@ protected BootJavaCodeLensEngine createCodeLensEngine(SpringSymbolIndex index, J
313320
return new BootJavaCodeLensEngine(this, codeLensProvider);
314321
}
315322

316-
protected BootJavaDocumentHighlightEngine createDocumentHighlightEngine(SpringSymbolIndex indexer) {
323+
protected BootJavaDocumentHighlightEngine createDocumentHighlightEngine(ApplicationContext appContext) {
317324
Collection<HighlightProvider> highlightProvider = new ArrayList<>();
318-
highlightProvider.add(new WebfluxRouteHighlightProdivder(indexer));
325+
highlightProvider.add(new WebfluxRouteHighlightProdivder(appContext.getBean(SpringSymbolIndex.class)));
326+
327+
Map<String, JdtAstDocHighlightsProvider> astHighlightProviders = appContext.getBeansOfType(JdtAstDocHighlightsProvider.class);
328+
if (!astHighlightProviders.isEmpty()) {
329+
highlightProvider.add(new JdtDocHighlightsProvider(projectFinder, cuCache, astHighlightProviders.values()));
330+
}
319331

320332
return new BootJavaDocumentHighlightEngine(this, highlightProvider);
321333
}
@@ -359,5 +371,10 @@ public Optional<SemanticTokensHandler> getSemanticTokensHandler() {
359371
return Optional.ofNullable(semanticTokensHandler);
360372
}
361373

374+
@Override
375+
public Optional<InlayHintHandler> getInlayHintHandler() {
376+
return Optional.ofNullable(inlayHintsHandler);
377+
}
378+
362379

363380
}

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2023 VMware, Inc.
2+
* Copyright (c) 2023, 2024 VMware, Inc.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -15,11 +15,12 @@
1515
import org.eclipse.jdt.core.dom.ASTNode;
1616
import org.eclipse.jdt.core.dom.CompilationUnit;
1717
import org.eclipse.lsp4j.LocationLink;
18+
import org.eclipse.lsp4j.TextDocumentIdentifier;
1819
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
1920
import org.springframework.ide.vscode.commons.java.IJavaProject;
2021

2122
public interface IJavaDefinitionProvider {
2223

23-
List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject project, CompilationUnit cu, ASTNode n);
24+
List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject project, TextDocumentIdentifier docId, CompilationUnit cu, ASTNode n, int offset);
2425

2526
}

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import org.eclipse.lsp4j.LocationLink;
2222
import org.eclipse.lsp4j.TextDocumentIdentifier;
2323
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
24+
import org.slf4j.Logger;
25+
import org.slf4j.LoggerFactory;
2426
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
2527
import org.springframework.ide.vscode.commons.java.IJavaProject;
2628
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
@@ -33,6 +35,8 @@
3335

3436
public class JavaDefinitionHandler implements DefinitionHandler, LanguageSpecific {
3537

38+
private static final Logger log = LoggerFactory.getLogger(JavaDefinitionHandler.class);
39+
3640
private CompilationUnitCache cuCache;
3741
private JavaProjectFinder projectFinder;
3842
private Collection<IJavaDefinitionProvider> providers;
@@ -64,7 +68,11 @@ public List<LocationLink> handle(CancelChecker cancelToken, DefinitionParams def
6468
if (cancelToken.isCanceled()) {
6569
break;
6670
}
67-
builder.addAll(provider.getDefinitions(cancelToken, project, cu, node));
71+
try {
72+
builder.addAll(provider.getDefinitions(cancelToken, project, doc, cu, node, start));
73+
} catch (Exception e) {
74+
log.error("", e);
75+
}
6876
}
6977
}
7078
return builder.build();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 Broadcom, Inc.
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, Inc. - initial API and implementation
10+
*******************************************************************************/
11+
package org.springframework.ide.vscode.boot.java;
12+
13+
import java.util.List;
14+
15+
import org.eclipse.jdt.core.dom.ASTNode;
16+
import org.eclipse.jdt.core.dom.CompilationUnit;
17+
import org.eclipse.lsp4j.DocumentHighlight;
18+
import org.springframework.ide.vscode.commons.java.IJavaProject;
19+
import org.springframework.ide.vscode.commons.util.text.TextDocument;
20+
21+
public interface JdtAstDocHighlightsProvider {
22+
23+
List<DocumentHighlight> getDocHighlights(IJavaProject project, TextDocument doc, CompilationUnit cu, ASTNode node, int offset);
24+
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 Broadcom, Inc.
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, Inc. - initial API and implementation
10+
*******************************************************************************/
11+
package org.springframework.ide.vscode.boot.java;
12+
13+
import java.net.URI;
14+
import java.util.Collection;
15+
import java.util.List;
16+
17+
import org.eclipse.jdt.core.dom.ASTNode;
18+
import org.eclipse.jdt.core.dom.NodeFinder;
19+
import org.eclipse.lsp4j.DocumentHighlight;
20+
import org.eclipse.lsp4j.Position;
21+
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
22+
import org.slf4j.Logger;
23+
import org.slf4j.LoggerFactory;
24+
import org.springframework.ide.vscode.boot.java.handlers.HighlightProvider;
25+
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
26+
import org.springframework.ide.vscode.commons.java.IJavaProject;
27+
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
28+
import org.springframework.ide.vscode.commons.util.text.TextDocument;
29+
30+
public class JdtDocHighlightsProvider implements HighlightProvider {
31+
32+
private static final Logger log = LoggerFactory.getLogger(JdtDocHighlightsProvider.class);
33+
34+
private final JavaProjectFinder projectFinder;
35+
private final CompilationUnitCache cuCache;
36+
private final Collection<JdtAstDocHighlightsProvider> astHighlightProviders;
37+
38+
39+
public JdtDocHighlightsProvider(JavaProjectFinder projectFinder, CompilationUnitCache cuCache, Collection<JdtAstDocHighlightsProvider> astHighlightProviders) {
40+
this.projectFinder = projectFinder;
41+
this.cuCache = cuCache;
42+
this.astHighlightProviders = astHighlightProviders;
43+
}
44+
45+
@Override
46+
public void provideHighlights(CancelChecker cancelToken, TextDocument doc, Position p,
47+
List<DocumentHighlight> resultAccumulator) {
48+
if (!astHighlightProviders.isEmpty()) {
49+
IJavaProject project = projectFinder.find(doc.getId()).orElse(null);
50+
if (project != null) {
51+
URI docUri = URI.create(doc.getUri());
52+
cuCache.withCompilationUnit(project, docUri, cu -> {
53+
if (cu != null) {
54+
int start = cu.getPosition(p.getLine() + 1, p.getCharacter());
55+
ASTNode node = NodeFinder.perform(cu, start, 0);
56+
for (JdtAstDocHighlightsProvider provider : astHighlightProviders) {
57+
try {
58+
resultAccumulator.addAll(provider.getDocHighlights(project, doc, cu, node, start));
59+
} catch (Throwable t) {
60+
log.error("", t);
61+
}
62+
}
63+
}
64+
return null;
65+
});
66+
}
67+
}
68+
}
69+
70+
}

0 commit comments

Comments
 (0)