Data query parameter go to definition, doc highlights and inlay hints
This commit is contained in:
@@ -31,7 +31,6 @@ import org.eclipse.lsp4j.DocumentSymbolParams;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.HoverParams;
|
||||
import org.eclipse.lsp4j.InlayHint;
|
||||
import org.eclipse.lsp4j.InlayHintParams;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.SemanticTokensLegend;
|
||||
import org.eclipse.lsp4j.SemanticTokensWithRegistrationOptions;
|
||||
@@ -175,15 +174,14 @@ public class CompositeLanguageServerComponents implements LanguageServerComponen
|
||||
this.inlayHintHandler = new InlayHintHandler() {
|
||||
|
||||
@Override
|
||||
public List<InlayHint> handle(CancelChecker token, InlayHintParams params) {
|
||||
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(params.getTextDocument().getUri());
|
||||
public List<InlayHint> handle(TextDocument doc, Range r, CancelChecker token) {
|
||||
LanguageId language = doc.getLanguageId();
|
||||
List<LanguageServerComponents> subComponents = componentsByLanguageId.get(language);
|
||||
if (subComponents != null) {
|
||||
return subComponents.stream()
|
||||
.map(sc -> sc.getInlayHintHandler())
|
||||
.filter(h -> h.isPresent())
|
||||
.flatMap(h -> h.get().handle(token, params).stream())
|
||||
.flatMap(h -> h.get().handle(doc, r, token).stream())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
// No applicable subEngine...
|
||||
|
||||
@@ -13,7 +13,12 @@ package org.springframework.ide.vscode.commons.languageserver.semantic.tokens;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
public record SemanticTokenData(int start, int end, String type, String[] modifiers) implements Comparable<SemanticTokenData>{
|
||||
public record SemanticTokenData(
|
||||
int start,
|
||||
int end,
|
||||
String type,
|
||||
String[] modifiers
|
||||
) implements Comparable<SemanticTokenData> {
|
||||
|
||||
@Override
|
||||
public int compareTo(SemanticTokenData o) {
|
||||
|
||||
@@ -13,11 +13,12 @@ package org.springframework.ide.vscode.commons.languageserver.util;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lsp4j.InlayHint;
|
||||
import org.eclipse.lsp4j.InlayHintParams;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
public interface InlayHintHandler {
|
||||
|
||||
List<InlayHint> handle(CancelChecker token, InlayHintParams params);
|
||||
List<InlayHint> handle(TextDocument doc, Range range, CancelChecker cancelChecker);
|
||||
|
||||
}
|
||||
|
||||
@@ -581,9 +581,12 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
InlayHintHandler handler = this.inlayHintHandler;
|
||||
|
||||
if (handler != null) {
|
||||
return CompletableFutures.computeAsync(messageWorkerThreadPool, cancelToken -> {
|
||||
return handler.handle(cancelToken, params);
|
||||
});
|
||||
TextDocument doc = getLatestSnapshot(params.getTextDocument().getUri());
|
||||
if (doc != null) {
|
||||
return CompletableFutures.computeAsync(messageWorkerThreadPool, cancelToken -> {
|
||||
return handler.handle(doc, params.getRange(), cancelToken);
|
||||
});
|
||||
}
|
||||
}
|
||||
return CompletableFuture.completedFuture(Collections.emptyList());
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.eclipse.lsp4j.CompletionItemTag;
|
||||
import org.eclipse.lsp4j.CompletionList;
|
||||
import org.eclipse.lsp4j.DefinitionParams;
|
||||
import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.eclipse.lsp4j.DocumentHighlight;
|
||||
import org.eclipse.lsp4j.DocumentSymbol;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.InsertReplaceEdit;
|
||||
@@ -240,6 +241,15 @@ public class Editor {
|
||||
assertEquals(ImmutableList.copyOf(expectedHighlights), actualHighlights);
|
||||
return ranges;
|
||||
}
|
||||
|
||||
public void assertDocumentHighlights(String afterString, DocumentHighlight... expected) throws Exception {
|
||||
int pos = getRawText().indexOf(afterString);
|
||||
if (pos>=0) {
|
||||
pos += afterString.length();
|
||||
}
|
||||
List<? extends DocumentHighlight> actual = harness.getDocumentHighlights(doc.getId(), doc.toPosition(pos));
|
||||
assertEquals(ImmutableList.copyOf(expected), actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the editor text, with cursor markers inserted (for easy textual comparison
|
||||
|
||||
@@ -35,6 +35,7 @@ import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -65,6 +66,8 @@ import org.eclipse.lsp4j.DidChangeTextDocumentParams;
|
||||
import org.eclipse.lsp4j.DidChangeWatchedFilesParams;
|
||||
import org.eclipse.lsp4j.DidCloseTextDocumentParams;
|
||||
import org.eclipse.lsp4j.DidOpenTextDocumentParams;
|
||||
import org.eclipse.lsp4j.DocumentHighlight;
|
||||
import org.eclipse.lsp4j.DocumentHighlightParams;
|
||||
import org.eclipse.lsp4j.DocumentSymbol;
|
||||
import org.eclipse.lsp4j.DocumentSymbolCapabilities;
|
||||
import org.eclipse.lsp4j.DocumentSymbolParams;
|
||||
@@ -679,6 +682,9 @@ public class LanguageServerHarness {
|
||||
return getServer().getTextDocumentService().codeLens(params).get();
|
||||
}
|
||||
|
||||
public List<? extends DocumentHighlight> getDocumentHighlights(TextDocumentIdentifier docId, Position cursor) throws InterruptedException, ExecutionException {
|
||||
return getServer().getTextDocumentService().documentHighlight(new DocumentHighlightParams(docId, cursor)).get();
|
||||
}
|
||||
|
||||
public CompletionItem resolveCompletionItem(CompletionItem maybeUnresolved) {
|
||||
if (getServer().hasLazyCompletionResolver()) {
|
||||
|
||||
@@ -48,6 +48,8 @@ import org.springframework.ide.vscode.boot.java.JavaDefinitionHandler;
|
||||
import org.springframework.ide.vscode.boot.java.beans.DependsOnDefinitionProvider;
|
||||
import org.springframework.ide.vscode.boot.java.beans.QualifierDefinitionProvider;
|
||||
import org.springframework.ide.vscode.boot.java.beans.ResourceDefinitionProvider;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.DataQueryParameterDefinitionProvider;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtDataQuerySemanticTokensProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaCodeActionProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaReconcileEngine;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.JavaCodeActionHandler;
|
||||
@@ -394,12 +396,13 @@ public class BootLanguageServerBootApp {
|
||||
}
|
||||
|
||||
@Bean
|
||||
JavaDefinitionHandler javaDefinitionHandler(CompilationUnitCache cuCache, JavaProjectFinder projectFinder, SpringMetamodelIndex springIndex) {
|
||||
JavaDefinitionHandler javaDefinitionHandler(SimpleLanguageServer server, CompilationUnitCache cuCache, JavaProjectFinder projectFinder, SpringMetamodelIndex springIndex, JdtDataQuerySemanticTokensProvider qurySemanticTokens) {
|
||||
return new JavaDefinitionHandler(cuCache, projectFinder, List.of(
|
||||
new ValueDefinitionProvider(),
|
||||
new DependsOnDefinitionProvider(springIndex),
|
||||
new ResourceDefinitionProvider(springIndex),
|
||||
new QualifierDefinitionProvider(springIndex)));
|
||||
new QualifierDefinitionProvider(springIndex),
|
||||
new DataQueryParameterDefinitionProvider(server.getTextDocumentService(), qurySemanticTokens)));
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -20,7 +20,9 @@ import org.springframework.ide.vscode.boot.java.cron.CronSemanticTokens;
|
||||
import org.springframework.ide.vscode.boot.java.cron.JdtCronReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.cron.JdtCronSemanticTokensProvider;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.HqlSemanticTokens;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtDataQueriesInlayHintsProvider;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtDataQuerySemanticTokensProvider;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryDocHighlightsProvider;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JpqlSemanticTokens;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JpqlSupportState;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.QueryJdtAstReconciler;
|
||||
@@ -130,6 +132,14 @@ public class JdtConfig {
|
||||
return new JdtDataQuerySemanticTokensProvider(jpqlProvider, hqlProvider, supportState, spelSemanticTokens);
|
||||
}
|
||||
|
||||
@Bean JdtDataQueriesInlayHintsProvider jdtDataQueriesInlayHintsProvider(JdtDataQuerySemanticTokensProvider semanticTokensProvider) {
|
||||
return new JdtDataQueriesInlayHintsProvider(semanticTokensProvider);
|
||||
}
|
||||
|
||||
@Bean JdtQueryDocHighlightsProvider jdtDocHighlightsProvider(JdtDataQuerySemanticTokensProvider semanticTokensProvider) {
|
||||
return new JdtQueryDocHighlightsProvider(semanticTokensProvider);
|
||||
}
|
||||
|
||||
@Bean JdtCronSemanticTokensProvider jdtCronSemanticTokensProvider(CronSemanticTokens cronProvider) {
|
||||
return new JdtCronSemanticTokensProvider(cronProvider);
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ import org.springframework.ide.vscode.commons.languageserver.util.CodeLensHandle
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentHighlightHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentSymbolHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.InlayHintHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.ReferencesHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
@@ -116,6 +117,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
private BootJavaCodeActionProvider codeActionProvider;
|
||||
private DocumentSymbolHandler docSymbolProvider;
|
||||
private JdtSemanticTokensHandler semanticTokensHandler;
|
||||
private JdtInlayHintsHandler inlayHintsHandler;
|
||||
|
||||
public BootJavaLanguageServerComponents(ApplicationContext appContext) {
|
||||
this.server = appContext.getBean(SimpleLanguageServer.class);
|
||||
@@ -176,7 +178,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
|
||||
codeLensHandler = createCodeLensEngine(springSymbolIndex, projectFinder, server);
|
||||
|
||||
highlightsEngine = createDocumentHighlightEngine(springSymbolIndex);
|
||||
highlightsEngine = createDocumentHighlightEngine(appContext);
|
||||
documents.onDocumentHighlight(highlightsEngine);
|
||||
|
||||
Map<String, JdtSemanticTokensProvider> jdtSemanticTokensProviders = appContext.getBeansOfType(JdtSemanticTokensProvider.class);
|
||||
@@ -184,6 +186,11 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
semanticTokensHandler = new JdtSemanticTokensHandler(cuCache, projectFinder, jdtSemanticTokensProviders.values());
|
||||
}
|
||||
|
||||
Map<String, JdtInlayHintsProvider> jdtInlayHintsProviders = appContext.getBeansOfType(JdtInlayHintsProvider.class);
|
||||
if (!jdtSemanticTokensProviders.isEmpty()) {
|
||||
inlayHintsHandler = new JdtInlayHintsHandler(cuCache, projectFinder, jdtInlayHintsProviders.values());
|
||||
}
|
||||
|
||||
config.addListener(ignore -> {
|
||||
log.info("update live process tracker settings - start");
|
||||
|
||||
@@ -313,9 +320,14 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
return new BootJavaCodeLensEngine(this, codeLensProvider);
|
||||
}
|
||||
|
||||
protected BootJavaDocumentHighlightEngine createDocumentHighlightEngine(SpringSymbolIndex indexer) {
|
||||
protected BootJavaDocumentHighlightEngine createDocumentHighlightEngine(ApplicationContext appContext) {
|
||||
Collection<HighlightProvider> highlightProvider = new ArrayList<>();
|
||||
highlightProvider.add(new WebfluxRouteHighlightProdivder(indexer));
|
||||
highlightProvider.add(new WebfluxRouteHighlightProdivder(appContext.getBean(SpringSymbolIndex.class)));
|
||||
|
||||
Map<String, JdtAstDocHighlightsProvider> astHighlightProviders = appContext.getBeansOfType(JdtAstDocHighlightsProvider.class);
|
||||
if (!astHighlightProviders.isEmpty()) {
|
||||
highlightProvider.add(new JdtDocHighlightsProvider(projectFinder, cuCache, astHighlightProviders.values()));
|
||||
}
|
||||
|
||||
return new BootJavaDocumentHighlightEngine(this, highlightProvider);
|
||||
}
|
||||
@@ -359,5 +371,10 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
return Optional.ofNullable(semanticTokensHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<InlayHintHandler> getInlayHintHandler() {
|
||||
return Optional.ofNullable(inlayHintsHandler);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* Copyright (c) 2023, 2024 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -15,11 +15,12 @@ import java.util.List;
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.lsp4j.LocationLink;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
|
||||
public interface IJavaDefinitionProvider {
|
||||
|
||||
List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject project, CompilationUnit cu, ASTNode n);
|
||||
List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject project, TextDocumentIdentifier docId, CompilationUnit cu, ASTNode n, int offset);
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ import org.eclipse.lsp4j.DefinitionParams;
|
||||
import org.eclipse.lsp4j.LocationLink;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
@@ -33,6 +35,8 @@ import com.google.common.collect.ImmutableList.Builder;
|
||||
|
||||
public class JavaDefinitionHandler implements DefinitionHandler, LanguageSpecific {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(JavaDefinitionHandler.class);
|
||||
|
||||
private CompilationUnitCache cuCache;
|
||||
private JavaProjectFinder projectFinder;
|
||||
private Collection<IJavaDefinitionProvider> providers;
|
||||
@@ -64,7 +68,11 @@ public class JavaDefinitionHandler implements DefinitionHandler, LanguageSpecifi
|
||||
if (cancelToken.isCanceled()) {
|
||||
break;
|
||||
}
|
||||
builder.addAll(provider.getDefinitions(cancelToken, project, cu, node));
|
||||
try {
|
||||
builder.addAll(provider.getDefinitions(cancelToken, project, doc, cu, node, start));
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.lsp4j.DocumentHighlight;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
public interface JdtAstDocHighlightsProvider {
|
||||
|
||||
List<DocumentHighlight> getDocHighlights(IJavaProject project, TextDocument doc, CompilationUnit cu, ASTNode node, int offset);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.NodeFinder;
|
||||
import org.eclipse.lsp4j.DocumentHighlight;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.HighlightProvider;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
public class JdtDocHighlightsProvider implements HighlightProvider {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(JdtDocHighlightsProvider.class);
|
||||
|
||||
private final JavaProjectFinder projectFinder;
|
||||
private final CompilationUnitCache cuCache;
|
||||
private final Collection<JdtAstDocHighlightsProvider> astHighlightProviders;
|
||||
|
||||
|
||||
public JdtDocHighlightsProvider(JavaProjectFinder projectFinder, CompilationUnitCache cuCache, Collection<JdtAstDocHighlightsProvider> astHighlightProviders) {
|
||||
this.projectFinder = projectFinder;
|
||||
this.cuCache = cuCache;
|
||||
this.astHighlightProviders = astHighlightProviders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provideHighlights(CancelChecker cancelToken, TextDocument doc, Position p,
|
||||
List<DocumentHighlight> resultAccumulator) {
|
||||
if (!astHighlightProviders.isEmpty()) {
|
||||
IJavaProject project = projectFinder.find(doc.getId()).orElse(null);
|
||||
if (project != null) {
|
||||
URI docUri = URI.create(doc.getUri());
|
||||
cuCache.withCompilationUnit(project, docUri, cu -> {
|
||||
if (cu != null) {
|
||||
int start = cu.getPosition(p.getLine() + 1, p.getCharacter());
|
||||
ASTNode node = NodeFinder.perform(cu, start, 0);
|
||||
for (JdtAstDocHighlightsProvider provider : astHighlightProviders) {
|
||||
try {
|
||||
resultAccumulator.addAll(provider.getDocHighlights(project, doc, cu, node, start));
|
||||
} catch (Throwable t) {
|
||||
log.error("", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.lsp4j.InlayHint;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.CompositeASTVisitor;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.InlayHintHandler;
|
||||
import org.springframework.ide.vscode.commons.util.Collector;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
public class JdtInlayHintsHandler implements InlayHintHandler {
|
||||
|
||||
private final CompilationUnitCache cuCache;
|
||||
private final JavaProjectFinder projectFinder;
|
||||
private final Collection<JdtInlayHintsProvider> inlayHintsProviders;
|
||||
|
||||
public JdtInlayHintsHandler(CompilationUnitCache cuCache, JavaProjectFinder projectFinder, Collection<JdtInlayHintsProvider> inlayHintsProviders) {
|
||||
this.cuCache = cuCache;
|
||||
this.projectFinder = projectFinder;
|
||||
this.inlayHintsProviders = inlayHintsProviders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<InlayHint> handle(TextDocument doc, Range range, CancelChecker cancelChecker) {
|
||||
Optional<IJavaProject> optProject = projectFinder.find(doc.getId());
|
||||
if (optProject.isPresent()) {
|
||||
IJavaProject jp = optProject.get();
|
||||
List<JdtInlayHintsProvider> applicableInlayHintsProviders = inlayHintsProviders.stream().filter(tp -> tp.isApplicable(jp)).collect(Collectors.toList());
|
||||
if (!applicableInlayHintsProviders.isEmpty()) {
|
||||
return cuCache.withCompilationUnit(jp, URI.create(doc.getUri()), cu -> computeInlayHints(applicableInlayHintsProviders, jp, cu, range, doc));
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private List<InlayHint> computeInlayHints(List<JdtInlayHintsProvider> applicableInlayHintsProviders, IJavaProject jp, CompilationUnit cu, Range r, TextDocument doc) {
|
||||
if (cu == null) {
|
||||
return null;
|
||||
}
|
||||
Collector<InlayHint> collector = new Collector<>();
|
||||
CompositeASTVisitor visitor = new CompositeASTVisitor();
|
||||
applicableInlayHintsProviders.forEach(p -> visitor.add(p.getInlayHintsComputer(jp, doc, cu, collector)));
|
||||
if (r != null) {
|
||||
if (r.getStart() != null) {
|
||||
visitor.setStartOffset(cu.getPosition(r.getStart().getLine(), r.getStart().getCharacter()));
|
||||
}
|
||||
if (r.getEnd() != null) {
|
||||
visitor.setEndOffset(cu.getPosition(r.getEnd().getLine(), r.getEnd().getCharacter()));
|
||||
}
|
||||
}
|
||||
cu.accept(visitor);
|
||||
return collector.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.lsp4j.InlayHint;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.Collector;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
public interface JdtInlayHintsProvider {
|
||||
|
||||
boolean isApplicable(IJavaProject project);
|
||||
ASTVisitor getInlayHintsComputer(IJavaProject project, TextDocument doc, CompilationUnit cu, Collector<InlayHint> collector);
|
||||
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.IAnnotationBinding;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.lsp4j.LocationLink;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
@@ -41,7 +42,7 @@ public class DependsOnDefinitionProvider implements IJavaDefinitionProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject project, CompilationUnit cu, ASTNode n) {
|
||||
public List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject project, TextDocumentIdentifier docId, CompilationUnit cu, ASTNode n, int offset) {
|
||||
if (n instanceof StringLiteral) {
|
||||
StringLiteral valueNode = (StringLiteral) n;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.IAnnotationBinding;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.lsp4j.LocationLink;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
@@ -41,7 +42,7 @@ public class QualifierDefinitionProvider implements IJavaDefinitionProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject project, CompilationUnit cu, ASTNode n) {
|
||||
public List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject project, TextDocumentIdentifier docId, CompilationUnit cu, ASTNode n, int offset) {
|
||||
if (n instanceof StringLiteral) {
|
||||
StringLiteral valueNode = (StringLiteral) n;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.IAnnotationBinding;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.lsp4j.LocationLink;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
@@ -41,7 +42,7 @@ public class ResourceDefinitionProvider implements IJavaDefinitionProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject project, CompilationUnit cu, ASTNode n) {
|
||||
public List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject project, TextDocumentIdentifier docId, CompilationUnit cu, ASTNode n, int offset) {
|
||||
if (n instanceof StringLiteral) {
|
||||
StringLiteral valueNode = (StringLiteral) n;
|
||||
|
||||
|
||||
@@ -14,11 +14,8 @@ import java.net.URI;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.QueryJdtAstReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitorUtils.EmbeddedExpression;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
@@ -49,22 +46,9 @@ public class JdtCronReconciler implements JdtAstReconciler {
|
||||
return new ASTVisitor() {
|
||||
@Override
|
||||
public boolean visit(NormalAnnotation node) {
|
||||
if (node.getTypeName() != null) {
|
||||
String fqn = node.getTypeName().getFullyQualifiedName();
|
||||
if (JdtCronSemanticTokensProvider.SCHEDULED_SIMPLE_NAME.equals(fqn) || Annotations.SCHEDULED.equals(fqn)) {
|
||||
ITypeBinding typeBinding = node.resolveTypeBinding();
|
||||
if (typeBinding != null && Annotations.SCHEDULED.equals(typeBinding.getQualifiedName())) {
|
||||
for (Object value : node.values()) {
|
||||
if (value instanceof MemberValuePair) {
|
||||
MemberValuePair pair = (MemberValuePair) value;
|
||||
String name = pair.getName().getFullyQualifiedName();
|
||||
if (name != null && "cron".equals(name) && JdtCronSemanticTokensProvider.isCronExpression(pair.getValue())) {
|
||||
QueryJdtAstReconciler.reconcileExpression(cronReconciler, pair.getValue(), problemCollector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EmbeddedExpression e = JdtCronVisitorUtils.extractCron(node);
|
||||
if (e != null) {
|
||||
cronReconciler.reconcile(e.text(), e.offset(), problemCollector);
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@@ -14,15 +14,9 @@ import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.Expression;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.jdt.core.dom.TextBlock;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.JdtSemanticTokensProvider;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtDataQuerySemanticTokensProvider;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitorUtils.EmbeddedExpression;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
|
||||
@@ -62,22 +56,9 @@ public class JdtCronSemanticTokensProvider implements JdtSemanticTokensProvider
|
||||
|
||||
@Override
|
||||
public boolean visit(NormalAnnotation node) {
|
||||
if (node.getTypeName() != null) {
|
||||
String fqn = node.getTypeName().getFullyQualifiedName();
|
||||
if (SCHEDULED_SIMPLE_NAME.equals(fqn) || Annotations.SCHEDULED.equals(fqn)) {
|
||||
ITypeBinding typeBinding = node.resolveTypeBinding();
|
||||
if (typeBinding != null && Annotations.SCHEDULED.equals(typeBinding.getQualifiedName())) {
|
||||
for (Object value : node.values()) {
|
||||
if (value instanceof MemberValuePair) {
|
||||
MemberValuePair pair = (MemberValuePair) value;
|
||||
String name = pair.getName().getFullyQualifiedName();
|
||||
if (name != null && "cron".equals(name) && isCronExpression(pair.getValue())) {
|
||||
JdtDataQuerySemanticTokensProvider.computeTokensForExpression(tokensProvider, pair.getValue()).forEach(collector::accept);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EmbeddedExpression e = JdtCronVisitorUtils.extractCron(node);
|
||||
if (e != null) {
|
||||
tokensProvider.computeTokens(e.text(), e.offset()).forEach(collector::accept);
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
@@ -85,19 +66,4 @@ public class JdtCronSemanticTokensProvider implements JdtSemanticTokensProvider
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean isCronExpression(Expression e) {
|
||||
String value = null;
|
||||
if (e instanceof StringLiteral sl) {
|
||||
value = sl.getLiteralValue();
|
||||
} else if (e instanceof TextBlock tb) {
|
||||
value = tb.getLiteralValue();
|
||||
}
|
||||
value = value.trim();
|
||||
if (value.startsWith("#{") || value.startsWith("${")) {
|
||||
// Either SPEL or Property Holder
|
||||
return false;
|
||||
}
|
||||
return value != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.cron;
|
||||
|
||||
import static org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitorUtils.extractEmbeddedExpression;
|
||||
|
||||
import org.eclipse.jdt.core.dom.Expression;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.jdt.core.dom.TextBlock;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitorUtils.EmbeddedExpression;
|
||||
|
||||
public class JdtCronVisitorUtils {
|
||||
|
||||
static final String SCHEDULED_SIMPLE_NAME = "Scheduled";
|
||||
|
||||
public static EmbeddedExpression extractCron(NormalAnnotation node) {
|
||||
if (node.getTypeName() != null) {
|
||||
String fqn = node.getTypeName().getFullyQualifiedName();
|
||||
if (SCHEDULED_SIMPLE_NAME.equals(fqn) || Annotations.SCHEDULED.equals(fqn)) {
|
||||
ITypeBinding typeBinding = node.resolveTypeBinding();
|
||||
if (typeBinding != null && Annotations.SCHEDULED.equals(typeBinding.getQualifiedName())) {
|
||||
for (Object value : node.values()) {
|
||||
if (value instanceof MemberValuePair) {
|
||||
MemberValuePair pair = (MemberValuePair) value;
|
||||
String name = pair.getName().getFullyQualifiedName();
|
||||
if (name != null && "cron".equals(name) && isCronExpression(pair.getValue())) {
|
||||
return extractEmbeddedExpression(pair.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isCronExpression(Expression e) {
|
||||
String value = null;
|
||||
if (e instanceof StringLiteral sl) {
|
||||
value = sl.getLiteralValue();
|
||||
} else if (e instanceof TextBlock tb) {
|
||||
value = tb.getLiteralValue();
|
||||
}
|
||||
value = value.trim();
|
||||
if (value.startsWith("#{") || value.startsWith("${")) {
|
||||
// Either SPEL or Property Holder
|
||||
return false;
|
||||
}
|
||||
return value != null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.jdt.core.dom.TextBlock;
|
||||
import org.eclipse.lsp4j.LocationLink;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.IJavaDefinitionProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.Collector;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
public class DataQueryParameterDefinitionProvider implements IJavaDefinitionProvider {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DataQueryParameterDefinitionProvider.class);
|
||||
|
||||
private final JdtDataQuerySemanticTokensProvider semanticTokensProvider;
|
||||
private final SimpleTextDocumentService documents;
|
||||
|
||||
public DataQueryParameterDefinitionProvider(SimpleTextDocumentService documents, JdtDataQuerySemanticTokensProvider semanticTokensProvider) {
|
||||
this.documents = documents;
|
||||
this.semanticTokensProvider = semanticTokensProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject project,
|
||||
TextDocumentIdentifier docId, CompilationUnit cu, ASTNode n, int offset) {
|
||||
if (n instanceof StringLiteral || n instanceof TextBlock) {
|
||||
|
||||
ASTNode a = JdtQueryDocHighlightsProvider.findQueryAnnotation(n);
|
||||
|
||||
TextDocument doc = documents.getLatestSnapshot(docId.getUri());
|
||||
|
||||
if (a.getParent() instanceof MethodDeclaration m && !m.parameters().isEmpty()) {
|
||||
Collector<SemanticTokenData> collector = new Collector<>();
|
||||
a.accept(semanticTokensProvider.getTokensComputer(project, doc, cu, collector));
|
||||
for (SemanticTokenData t : collector.get()) {
|
||||
if ("parameter".equals(t.type()) && t.start() <= offset && offset <= t.end()) {
|
||||
try {
|
||||
String parameterDescriptor = doc.get(t.start(), t.end() - t.start());
|
||||
SimpleName paramName = JdtQueryDocHighlightsProvider.findParameter(m, parameterDescriptor);
|
||||
if (paramName != null) {
|
||||
LocationLink link = new LocationLink();
|
||||
link.setTargetUri(docId.getUri());
|
||||
link.setOriginSelectionRange(doc.toRange(t.start(), t.end() - t.start()));
|
||||
link.setTargetSelectionRange(doc.toRange(paramName.getStartPosition(), paramName.getLength()));
|
||||
link.setTargetRange(link.getTargetSelectionRange());
|
||||
return List.of(link);
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -146,6 +146,9 @@ public class HqlSemanticTokens implements SemanticTokensDataProvider {
|
||||
if (ctx.identifier() != null && ctx.identifier().getStart() != null) {
|
||||
semantics.put(ctx.identifier().getStart(), "parameter");
|
||||
}
|
||||
if (ctx.INTEGER_LITERAL() != null) {
|
||||
semantics.put(ctx.INTEGER_LITERAL().getSymbol(), "parameter");
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
|
||||
import org.eclipse.lsp4j.InlayHint;
|
||||
import org.eclipse.lsp4j.InlayHintKind;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.springframework.ide.vscode.boot.java.JdtInlayHintsProvider;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitorUtils.EmbeddedQueryExpression;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.Collector;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
public class JdtDataQueriesInlayHintsProvider implements JdtInlayHintsProvider {
|
||||
|
||||
private final JdtDataQuerySemanticTokensProvider semanticTokensProvider;
|
||||
|
||||
|
||||
public JdtDataQueriesInlayHintsProvider(JdtDataQuerySemanticTokensProvider semanticTokensProvider) {
|
||||
this.semanticTokensProvider = semanticTokensProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(IJavaProject project) {
|
||||
return semanticTokensProvider.isApplicable(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ASTVisitor getInlayHintsComputer(IJavaProject project, TextDocument doc, CompilationUnit cu,
|
||||
Collector<InlayHint> collector) {
|
||||
return new ASTVisitor() {
|
||||
|
||||
@Override
|
||||
public boolean visit(NormalAnnotation node) {
|
||||
if (node.getParent() instanceof MethodDeclaration m && !m.parameters().isEmpty()) {
|
||||
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(node);
|
||||
if (q != null) {
|
||||
processQuery(project, doc, collector, m, q);
|
||||
}
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SingleMemberAnnotation node) {
|
||||
if (node.getParent() instanceof MethodDeclaration m && !m.parameters().isEmpty()) {
|
||||
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(node);
|
||||
if (q != null) {
|
||||
processQuery(project, doc, collector, m, q);
|
||||
}
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private void processQuery(IJavaProject project, TextDocument doc, Collector<InlayHint> collector, MethodDeclaration m, EmbeddedQueryExpression q) {
|
||||
List<SemanticTokenData> semanticTokens = semanticTokensProvider.computeSemanticTokens(project, q.query().text(), q.query().offset(), q.isNative());
|
||||
for (SemanticTokenData t : semanticTokens) {
|
||||
if ("parameter".equals(t.type())) {
|
||||
try {
|
||||
int number = Integer.parseInt(doc.get(t.start(), t.end() - t.start()));
|
||||
if (number > 0 && number <= m.parameters().size()) {
|
||||
Object param = m.parameters().get(number - 1);
|
||||
if (param instanceof SingleVariableDeclaration svd) {
|
||||
String paramName = svd.getName().getIdentifier();
|
||||
InlayHint hint = new InlayHint();
|
||||
hint.setKind(InlayHintKind.Parameter);
|
||||
hint.setLabel(Either.forLeft(paramName));
|
||||
hint.setPaddingLeft(true);
|
||||
hint.setPosition(doc.toPosition(t.end()));
|
||||
|
||||
collector.accept(hint);
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// ignore
|
||||
} catch (BadLocationException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,20 +19,12 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.Expression;
|
||||
import org.eclipse.jdt.core.dom.IMethodBinding;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.MethodInvocation;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.jdt.core.dom.TextBlock;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.JdtSemanticTokensProvider;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitorUtils.EmbeddedQueryExpression;
|
||||
import org.springframework.ide.vscode.boot.java.spel.SpelSemanticTokens;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
@@ -43,9 +35,6 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
public class JdtDataQuerySemanticTokensProvider implements JdtSemanticTokensProvider {
|
||||
|
||||
private static final String QUERY = "Query";
|
||||
private static final String NAMED_QUERY = "NamedQuery";
|
||||
|
||||
private final JpqlSemanticTokens jpqlProvider;
|
||||
private final HqlSemanticTokens hqlProvider;
|
||||
private final JpqlSupportState supportState;
|
||||
@@ -74,126 +63,43 @@ public class JdtDataQuerySemanticTokensProvider implements JdtSemanticTokensProv
|
||||
|
||||
@Override
|
||||
public ASTVisitor getTokensComputer(IJavaProject jp, TextDocument doc, CompilationUnit cu, Collector<SemanticTokenData> tokensData) {
|
||||
SemanticTokensDataProvider provider = SpringProjectUtil.hasDependencyStartingWith(jp, "hibernate-core", null) ? hqlProvider : jpqlProvider;
|
||||
return new ASTVisitor() {
|
||||
@Override
|
||||
public boolean visit(NormalAnnotation a) {
|
||||
Expression queryExpression = null;
|
||||
boolean isNative = false;
|
||||
if (isQueryAnnotation(a)) {
|
||||
for (Object value : a.values()) {
|
||||
if (value instanceof MemberValuePair) {
|
||||
MemberValuePair pair = (MemberValuePair) value;
|
||||
String name = pair.getName().getFullyQualifiedName();
|
||||
if (name != null) {
|
||||
switch (name) {
|
||||
case "value":
|
||||
queryExpression = pair.getValue();
|
||||
break;
|
||||
case "nativeQuery":
|
||||
Expression expression = pair.getValue();
|
||||
if (expression != null) {
|
||||
Object o = expression.resolveConstantExpressionValue();
|
||||
if (o instanceof Boolean b) {
|
||||
isNative = b.booleanValue();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isNamedQueryAnnotation(a)) {
|
||||
for (Object value : a.values()) {
|
||||
if (value instanceof MemberValuePair) {
|
||||
MemberValuePair pair = (MemberValuePair) value;
|
||||
String name = pair.getName().getFullyQualifiedName();
|
||||
if (name != null) {
|
||||
switch (name) {
|
||||
case "query":
|
||||
queryExpression = pair.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(a);
|
||||
if (q != null) {
|
||||
computeSemanticTokens(jp, q.query().text(), q.query().offset(), q.isNative()).forEach(tokensData::accept);
|
||||
}
|
||||
|
||||
if (queryExpression != null) {
|
||||
if (isNative) {
|
||||
computeTokensForExpression(getSqlSemanticTokensProvider(jp), queryExpression).forEach(tokensData::accept);
|
||||
} else {
|
||||
computeTokensForExpression(provider, queryExpression).forEach(tokensData::accept);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return super.visit(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SingleMemberAnnotation a) {
|
||||
if (isQueryAnnotation(a)) {
|
||||
computeTokensForExpression(provider, a.getValue()).forEach(tokensData::accept);
|
||||
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(a);
|
||||
if (q != null) {
|
||||
computeSemanticTokens(jp, q.query().text(), q.query().offset(), q.isNative()).forEach(tokensData::accept);
|
||||
}
|
||||
return false;
|
||||
return super.visit(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MethodInvocation node) {
|
||||
if ("createQuery".equals(node.getName().getIdentifier()) && node.arguments().size() <= 2 && node.arguments().get(0) instanceof Expression queryExpr) {
|
||||
IMethodBinding methodBinding = node.resolveMethodBinding();
|
||||
if ("jakarta.persistence.EntityManager".equals(methodBinding.getDeclaringClass().getQualifiedName())) {
|
||||
if (methodBinding.getParameterTypes().length <= 2 && "java.lang.String".equals(methodBinding.getParameterTypes()[0].getQualifiedName())) {
|
||||
computeTokensForExpression(provider, queryExpr).forEach(tokensData::accept);
|
||||
}
|
||||
}
|
||||
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(node);
|
||||
if (q != null) {
|
||||
computeSemanticTokens(jp, q.query().text(), q.query().offset(), q.isNative()).forEach(tokensData::accept);
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static List<SemanticTokenData> computeTokensForExpression(SemanticTokensDataProvider provider, Expression valueExp) {
|
||||
String query = null;
|
||||
int offset = 0;
|
||||
if (valueExp instanceof StringLiteral sl) {
|
||||
query = sl.getEscapedValue();
|
||||
query = query.substring(1, query.length() - 1);
|
||||
offset = sl.getStartPosition() + 1; // +1 to skip over opening "
|
||||
} else if (valueExp instanceof TextBlock tb) {
|
||||
query = tb.getEscapedValue();
|
||||
query = query.substring(3, query.length() - 3);
|
||||
offset = tb.getStartPosition() + 3; // +3 to skip over opening """
|
||||
}
|
||||
|
||||
if (query != null) {
|
||||
public List<SemanticTokenData> computeSemanticTokens(IJavaProject jp, String query, int offset, boolean isNative) {
|
||||
SemanticTokensDataProvider provider = isNative ? getSqlSemanticTokensProvider(jp) : (SpringProjectUtil.hasDependencyStartingWith(jp, "hibernate-core", null) ? hqlProvider : jpqlProvider);
|
||||
if (provider != null) {
|
||||
return provider.computeTokens(query, offset);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
static boolean isQueryAnnotation(Annotation a) {
|
||||
if (Annotations.DATA_QUERY.equals(a.getTypeName().getFullyQualifiedName()) || QUERY.equals(a.getTypeName().getFullyQualifiedName())) {
|
||||
ITypeBinding type = a.resolveTypeBinding();
|
||||
if (type != null) {
|
||||
return AnnotationHierarchies.hasTransitiveSuperAnnotationType(type, Annotations.DATA_QUERY);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean isNamedQueryAnnotation(Annotation a) {
|
||||
if (NAMED_QUERY.equals(a.getTypeName().getFullyQualifiedName()) || Annotations.JPA_JAKARTA_NAMED_QUERY.equals(a.getTypeName().getFullyQualifiedName())
|
||||
|| Annotations.JPA_JAVAX_NAMED_QUERY.equals(a.getTypeName().getFullyQualifiedName())) {
|
||||
ITypeBinding type = a.resolveTypeBinding();
|
||||
if (type != null) {
|
||||
return AnnotationHierarchies.hasTransitiveSuperAnnotationType(type, Annotations.JPA_JAKARTA_NAMED_QUERY)
|
||||
|| AnnotationHierarchies.hasTransitiveSuperAnnotationType(type, Annotations.JPA_JAVAX_NAMED_QUERY);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(IJavaProject project) {
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.jdt.core.dom.TextBlock;
|
||||
import org.eclipse.jdt.core.dom.VariableDeclaration;
|
||||
import org.eclipse.lsp4j.DocumentHighlight;
|
||||
import org.eclipse.lsp4j.DocumentHighlightKind;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.JdtAstDocHighlightsProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.Collector;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
public class JdtQueryDocHighlightsProvider implements JdtAstDocHighlightsProvider {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(JdtQueryDocHighlightsProvider.class);
|
||||
|
||||
private JdtDataQuerySemanticTokensProvider semanticTokensProvider;
|
||||
|
||||
public JdtQueryDocHighlightsProvider(JdtDataQuerySemanticTokensProvider semanticTokensProvider) {
|
||||
this.semanticTokensProvider = semanticTokensProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DocumentHighlight> getDocHighlights(IJavaProject project, TextDocument doc, CompilationUnit cu,
|
||||
ASTNode node, int offset) {
|
||||
if (node instanceof StringLiteral || node instanceof TextBlock) {
|
||||
Annotation a = findQueryAnnotation(node);
|
||||
if (a != null && a.getParent() instanceof MethodDeclaration m && !m.parameters().isEmpty()) {
|
||||
Collector<SemanticTokenData> collector = new Collector<>();
|
||||
a.accept(semanticTokensProvider.getTokensComputer(project, doc, cu, collector));
|
||||
for (SemanticTokenData t : collector.get()) {
|
||||
if ("parameter".equals(t.type()) && t.start() <= offset && offset <= t.end()) {
|
||||
try {
|
||||
String parameterDescriptor = doc.get(t.start(), t.end() - t.start());
|
||||
SimpleName paramName = findParameter(m, parameterDescriptor);
|
||||
if (paramName != null) {
|
||||
DocumentHighlight highlight = new DocumentHighlight();
|
||||
highlight.setKind(DocumentHighlightKind.Write);
|
||||
highlight.setRange(doc.toRange(paramName.getStartPosition(), paramName.getLength()));
|
||||
return List.of(highlight);
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
static Annotation findQueryAnnotation(ASTNode node) {
|
||||
if (node.getParent() instanceof MemberValuePair pair
|
||||
&& node.getParent().getParent() instanceof NormalAnnotation na && "value".equals(pair.getName().getIdentifier())
|
||||
&& JdtQueryVisitorUtils.isQueryAnnotation(na)) {
|
||||
return na;
|
||||
} else if (node.getParent() instanceof SingleMemberAnnotation sm
|
||||
&& JdtQueryVisitorUtils.isQueryAnnotation(sm)) {
|
||||
return sm;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static SimpleName findParameter(MethodDeclaration m, String p) {
|
||||
try {
|
||||
int paramNumber = Integer.parseInt(p);
|
||||
if (paramNumber > 0 && paramNumber <= m.parameters().size()) {
|
||||
Object o = m.parameters().get(paramNumber - 1);
|
||||
if (o instanceof VariableDeclaration vd) {
|
||||
return vd.getName();
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
for (Object o : m.parameters()) {
|
||||
if (o instanceof VariableDeclaration vd) {
|
||||
SimpleName simpleName = vd.getName();
|
||||
if (simpleName != null && p.equals(simpleName.getIdentifier())) {
|
||||
return simpleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
|
||||
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.Expression;
|
||||
import org.eclipse.jdt.core.dom.IMethodBinding;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.MethodInvocation;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.jdt.core.dom.TextBlock;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
|
||||
|
||||
public class JdtQueryVisitorUtils {
|
||||
|
||||
private static final String QUERY = "Query";
|
||||
private static final String NAMED_QUERY = "NamedQuery";
|
||||
|
||||
|
||||
public record EmbeddedExpression(Expression expression, String text, int offset) {};
|
||||
|
||||
public record EmbeddedQueryExpression(EmbeddedExpression query, boolean isNative) {};
|
||||
|
||||
public static EmbeddedQueryExpression extractQueryExpression(SingleMemberAnnotation a) {
|
||||
if (isQueryAnnotation(a)) {
|
||||
EmbeddedExpression expression = extractEmbeddedExpression(a.getValue());
|
||||
return expression == null ? null : new EmbeddedQueryExpression(expression, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static EmbeddedQueryExpression extractQueryExpression(NormalAnnotation a) {
|
||||
Expression queryExpression = null;
|
||||
boolean isNative = false;
|
||||
if (isQueryAnnotation(a)) {
|
||||
for (Object value : a.values()) {
|
||||
if (value instanceof MemberValuePair) {
|
||||
MemberValuePair pair = (MemberValuePair) value;
|
||||
String name = pair.getName().getFullyQualifiedName();
|
||||
if (name != null) {
|
||||
switch (name) {
|
||||
case "value":
|
||||
queryExpression = pair.getValue();
|
||||
break;
|
||||
case "nativeQuery":
|
||||
Expression expression = pair.getValue();
|
||||
if (expression != null) {
|
||||
Object o = expression.resolveConstantExpressionValue();
|
||||
if (o instanceof Boolean b) {
|
||||
isNative = b.booleanValue();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isNamedQueryAnnotation(a)) {
|
||||
for (Object value : a.values()) {
|
||||
if (value instanceof MemberValuePair) {
|
||||
MemberValuePair pair = (MemberValuePair) value;
|
||||
String name = pair.getName().getFullyQualifiedName();
|
||||
if (name != null) {
|
||||
switch (name) {
|
||||
case "query":
|
||||
queryExpression = pair.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (queryExpression != null) {
|
||||
EmbeddedExpression e = extractEmbeddedExpression(queryExpression);
|
||||
if (e != null) {
|
||||
return new EmbeddedQueryExpression(e, isNative);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static EmbeddedQueryExpression extractQueryExpression(MethodInvocation m) {
|
||||
if ("createQuery".equals(m.getName().getIdentifier()) && m.arguments().size() <= 2 && m.arguments().get(0) instanceof Expression queryExpr) {
|
||||
IMethodBinding methodBinding = m.resolveMethodBinding();
|
||||
if ("jakarta.persistence.EntityManager".equals(methodBinding.getDeclaringClass().getQualifiedName())) {
|
||||
if (methodBinding.getParameterTypes().length <= 2 && "java.lang.String".equals(methodBinding.getParameterTypes()[0].getQualifiedName())) {
|
||||
EmbeddedExpression expression = extractEmbeddedExpression(queryExpr);
|
||||
return expression == null ? null : new EmbeddedQueryExpression(expression, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static EmbeddedExpression extractEmbeddedExpression(Expression valueExp) {
|
||||
String text = null;
|
||||
int offset = 0;
|
||||
if (valueExp instanceof StringLiteral sl) {
|
||||
text = sl.getEscapedValue();
|
||||
text = text.substring(1, text.length() - 1);
|
||||
offset = sl.getStartPosition() + 1; // +1 to skip over opening "
|
||||
} else if (valueExp instanceof TextBlock tb) {
|
||||
text = tb.getEscapedValue();
|
||||
text = text.substring(3, text.length() - 3);
|
||||
offset = tb.getStartPosition() + 3; // +3 to skip over opening """
|
||||
}
|
||||
return text == null ? null : new EmbeddedExpression(valueExp, text, offset);
|
||||
}
|
||||
|
||||
|
||||
static boolean isQueryAnnotation(Annotation a) {
|
||||
if (Annotations.DATA_QUERY.equals(a.getTypeName().getFullyQualifiedName()) || QUERY.equals(a.getTypeName().getFullyQualifiedName())) {
|
||||
ITypeBinding type = a.resolveTypeBinding();
|
||||
if (type != null) {
|
||||
return AnnotationHierarchies.hasTransitiveSuperAnnotationType(type, Annotations.DATA_QUERY);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean isNamedQueryAnnotation(Annotation a) {
|
||||
if (NAMED_QUERY.equals(a.getTypeName().getFullyQualifiedName()) || Annotations.JPA_JAKARTA_NAMED_QUERY.equals(a.getTypeName().getFullyQualifiedName())
|
||||
|| Annotations.JPA_JAVAX_NAMED_QUERY.equals(a.getTypeName().getFullyQualifiedName())) {
|
||||
ITypeBinding type = a.resolveTypeBinding();
|
||||
if (type != null) {
|
||||
return AnnotationHierarchies.hasTransitiveSuperAnnotationType(type, Annotations.JPA_JAKARTA_NAMED_QUERY)
|
||||
|| AnnotationHierarchies.hasTransitiveSuperAnnotationType(type, Annotations.JPA_JAVAX_NAMED_QUERY);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -157,6 +157,9 @@ public class JpqlSemanticTokens implements SemanticTokensDataProvider {
|
||||
if (ctx.identification_variable() != null && ctx.identification_variable().getStart() != null) {
|
||||
semantics.put(ctx.identification_variable().getStart(), "parameter");
|
||||
}
|
||||
if (ctx.INTLITERAL() != null) {
|
||||
semantics.put(ctx.INTLITERAL().getSymbol(), "parameter");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,13 +18,12 @@ import java.util.Optional;
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.Expression;
|
||||
import org.eclipse.jdt.core.dom.IMethodBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.MethodInvocation;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.jdt.core.dom.TextBlock;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitorUtils.EmbeddedQueryExpression;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.Reconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.RequiredCompleteAstException;
|
||||
@@ -61,77 +60,28 @@ public class QueryJdtAstReconciler implements JdtAstReconciler {
|
||||
|
||||
@Override
|
||||
public boolean visit(NormalAnnotation node) {
|
||||
|
||||
Expression queryExpression = null;
|
||||
boolean isNative = false;
|
||||
if (JdtDataQuerySemanticTokensProvider.isQueryAnnotation(node)) {
|
||||
for (Object value : node.values()) {
|
||||
if (value instanceof MemberValuePair) {
|
||||
MemberValuePair pair = (MemberValuePair) value;
|
||||
String name = pair.getName().getFullyQualifiedName();
|
||||
if (name != null) {
|
||||
switch (name) {
|
||||
case "value":
|
||||
queryExpression = pair.getValue();
|
||||
break;
|
||||
case "nativeQuery":
|
||||
Expression expression = pair.getValue();
|
||||
if (expression != null) {
|
||||
Object o = expression.resolveConstantExpressionValue();
|
||||
if (o instanceof Boolean b) {
|
||||
isNative = b.booleanValue();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (JdtDataQuerySemanticTokensProvider.isNamedQueryAnnotation(node)) {
|
||||
for (Object value : node.values()) {
|
||||
if (value instanceof MemberValuePair) {
|
||||
MemberValuePair pair = (MemberValuePair) value;
|
||||
String name = pair.getName().getFullyQualifiedName();
|
||||
if (name != null) {
|
||||
switch (name) {
|
||||
case "query":
|
||||
queryExpression = pair.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(node);
|
||||
if (q != null) {
|
||||
Optional<Reconciler> reconcilerOpt = q.isNative() ? getSqlReconciler(project) : Optional.of(getQueryReconciler(project));
|
||||
reconcilerOpt.ifPresent(r -> r.reconcile(q.query().text(), q.query().offset(), problemCollector));
|
||||
}
|
||||
|
||||
if (queryExpression != null) {
|
||||
if (isNative) {
|
||||
final Expression expr = queryExpression;
|
||||
getSqlReconciler(project).ifPresent(r -> reconcileExpression(r, expr, problemCollector));
|
||||
} else {
|
||||
reconcileExpression(getQueryReconciler(project), queryExpression, problemCollector);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SingleMemberAnnotation node) {
|
||||
if (JdtDataQuerySemanticTokensProvider.isQueryAnnotation(node)) {
|
||||
reconcileExpression(getQueryReconciler(project), node.getValue(), problemCollector);
|
||||
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(node);
|
||||
if (q != null) {
|
||||
getQueryReconciler(project).reconcile(q.query().text(), q.query().offset(), problemCollector);
|
||||
}
|
||||
return false;
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MethodInvocation node) {
|
||||
if ("createQuery".equals(node.getName().getIdentifier()) && node.arguments().size() <= 2 && node.arguments().get(0) instanceof Expression queryExpr) {
|
||||
IMethodBinding methodBinding = node.resolveMethodBinding();
|
||||
if ("jakarta.persistence.EntityManager".equals(methodBinding.getDeclaringClass().getQualifiedName())) {
|
||||
if (methodBinding.getParameterTypes().length <= 2 && "java.lang.String".equals(methodBinding.getParameterTypes()[0].getQualifiedName())) {
|
||||
reconcileExpression(getQueryReconciler(project), queryExpr, problemCollector);
|
||||
}
|
||||
}
|
||||
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(node);
|
||||
if (q != null) {
|
||||
getQueryReconciler(project).reconcile(q.query().text(), q.query().offset(), problemCollector);
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@@ -10,10 +10,8 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.value;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -32,6 +30,7 @@ import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.LocationLink;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -80,7 +79,8 @@ public class ValueDefinitionProvider implements IJavaDefinitionProvider {
|
||||
);
|
||||
|
||||
@Override
|
||||
public List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject project, CompilationUnit cu, ASTNode n) {
|
||||
public List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject project,
|
||||
TextDocumentIdentifier docId, CompilationUnit cu, ASTNode n, int offset) {
|
||||
|
||||
if (n instanceof StringLiteral) {
|
||||
StringLiteral valueNode = (StringLiteral) n;
|
||||
@@ -283,6 +283,4 @@ public class ValueDefinitionProvider implements IJavaDefinitionProvider {
|
||||
return resources;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ import org.eclipse.lsp4j.Command;
|
||||
import org.eclipse.lsp4j.InlayHint;
|
||||
import org.eclipse.lsp4j.InlayHintKind;
|
||||
import org.eclipse.lsp4j.InlayHintLabelPart;
|
||||
import org.eclipse.lsp4j.InlayHintParams;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -55,12 +55,10 @@ public class PomInlayHintHandler implements InlayHintHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(PomInlayHintHandler.class);
|
||||
|
||||
final private SimpleLanguageServer server;
|
||||
final private JavaProjectFinder projectFinder;
|
||||
final private SpringProjectsProvider generationsProvider;
|
||||
|
||||
public PomInlayHintHandler(SimpleLanguageServer server, JavaProjectFinder projectFinder, ProjectObserver projectObserver, SpringProjectsProvider generationsProvider) {
|
||||
this.server = server;
|
||||
this.projectFinder = projectFinder;
|
||||
this.generationsProvider = generationsProvider;
|
||||
|
||||
@@ -99,13 +97,13 @@ public class PomInlayHintHandler implements InlayHintHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<InlayHint> handle(CancelChecker token, InlayHintParams params) {
|
||||
URI uri = URI.create(params.getTextDocument().getUri());
|
||||
public List<InlayHint> handle(TextDocument doc, Range range, CancelChecker cancelChecker) {
|
||||
URI uri = URI.create(doc.getUri());
|
||||
if ("file".equals(uri.getScheme()) && POM_XML.equals(Paths.get(uri).getFileName().toString())) {
|
||||
|
||||
List<InlayHintWithLazyPosition> inlayHintProviders = new ArrayList<>();
|
||||
|
||||
Optional<IJavaProject> projectOpt = projectFinder.find(params.getTextDocument());
|
||||
Optional<IJavaProject> projectOpt = projectFinder.find(doc.getId());
|
||||
if (projectOpt.isPresent()) {
|
||||
|
||||
IJavaProject jp = projectOpt.get();
|
||||
@@ -194,20 +192,15 @@ public class PomInlayHintHandler implements InlayHintHandler {
|
||||
}
|
||||
|
||||
if (!inlayHintProviders.isEmpty()) {
|
||||
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(params.getTextDocument().getUri());
|
||||
|
||||
if (doc != null) {
|
||||
String content = doc.get();
|
||||
if (!content.isEmpty()) {
|
||||
// if doc is not empty, dive into the details and provide more sophisticated content assist proposals
|
||||
DOMParser parser = DOMParser.getInstance();
|
||||
DOMDocument dom = parser.parse(content, "", null);
|
||||
String content = doc.get();
|
||||
if (!content.isEmpty()) {
|
||||
DOMParser parser = DOMParser.getInstance();
|
||||
DOMDocument dom = parser.parse(content, "", null);
|
||||
|
||||
DOMElement project = dom.getDocumentElement();
|
||||
DOMElement project = dom.getDocumentElement();
|
||||
|
||||
if (project != null && "project".equals(project.getTagName())) {
|
||||
return inlayHintProviders.stream().flatMap(provider -> provider.computeInlayHints(doc, project).stream()).collect(Collectors.toList());
|
||||
}
|
||||
if (project != null && "project".equals(project.getTagName())) {
|
||||
return inlayHintProviders.stream().flatMap(provider -> provider.computeInlayHints(doc, project).stream()).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
|
||||
import org.springframework.ide.vscode.boot.bootiful.HoverTestConf;
|
||||
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@BootLanguageServerTest
|
||||
@Import(HoverTestConf.class)
|
||||
public class DataQueryParameterDefinitionProviderTest {
|
||||
|
||||
@Autowired BootLanguageServerHarness harness;
|
||||
|
||||
private ProjectsHarness projects = ProjectsHarness.INSTANCE;
|
||||
|
||||
private MavenJavaProject jp;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws Exception {
|
||||
jp = projects.mavenProject("boot-mysql");
|
||||
harness.useProject(jp);
|
||||
}
|
||||
|
||||
@Test
|
||||
void parameterNameDefinition() throws Exception {
|
||||
String source = """
|
||||
package my.package
|
||||
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
public interface OwnerRepository {
|
||||
|
||||
@Query("SELECT DISTINCT owner FROM Owner owner left join owner.pets WHERE owner.lastName LIKE :lastName%")
|
||||
Object findByLastName(@Param("lastName") String lastName);
|
||||
}
|
||||
""";
|
||||
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA, source, Paths.get(jp.getLocationUri()).resolve("src/main/resource/my/package/OwnerRepository.java").toUri().toASCIIString());
|
||||
|
||||
Range expectedRange = editor.rangeOf("String lastName", "lastName");
|
||||
Range highlightRange = editor.rangeOf(":lastName%", "lastName");
|
||||
editor.assertGotoDefinition(highlightRange.getStart(), expectedRange, highlightRange);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void parameterOrdinalDefinition() throws Exception {
|
||||
String source = """
|
||||
package my.package
|
||||
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
public interface OwnerRepository {
|
||||
|
||||
@Query("SELECT DISTINCT owner FROM Owner owner left join owner.pets WHERE owner.lastName LIKE :1%")
|
||||
Object findByLastName(@Param("lastName") String lastName);
|
||||
}
|
||||
""";
|
||||
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA, source, Paths.get(jp.getLocationUri()).resolve("src/main/resource/my/package/OwnerRepository.java").toUri().toASCIIString());
|
||||
|
||||
Range expectedRange = editor.rangeOf("String lastName", "lastName");
|
||||
Range highlightRange = editor.rangeOf(":1%", "1");
|
||||
editor.assertGotoDefinition(highlightRange.getStart(), expectedRange, highlightRange);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import org.eclipse.lsp4j.DocumentHighlight;
|
||||
import org.eclipse.lsp4j.DocumentHighlightKind;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
|
||||
import org.springframework.ide.vscode.boot.bootiful.HoverTestConf;
|
||||
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@BootLanguageServerTest
|
||||
@Import(HoverTestConf.class)
|
||||
public class JdtQueryDocHighlightsProviderTest {
|
||||
|
||||
@Autowired BootLanguageServerHarness harness;
|
||||
|
||||
private ProjectsHarness projects = ProjectsHarness.INSTANCE;
|
||||
|
||||
private MavenJavaProject jp;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws Exception {
|
||||
jp = projects.mavenProject("boot-mysql");
|
||||
harness.useProject(jp);
|
||||
}
|
||||
|
||||
@Test
|
||||
void parameterName() throws Exception {
|
||||
String source = """
|
||||
package my.package
|
||||
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
public interface OwnerRepository {
|
||||
|
||||
@Query("SELECT DISTINCT owner FROM Owner owner left join owner.pets WHERE owner.lastName LIKE :lastName%")
|
||||
Object findByLastName(@Param("lastName") String lastName);
|
||||
}
|
||||
""";
|
||||
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA, source, Paths.get(jp.getLocationUri()).resolve("src/main/resource/my/package/OwnerRepository.java").toUri().toASCIIString());
|
||||
|
||||
editor.assertDocumentHighlights(":lastName", new DocumentHighlight(editor.rangeOf("String lastName", "lastName"), DocumentHighlightKind.Write));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void parameterOrdinal() throws Exception {
|
||||
String source = """
|
||||
package my.package
|
||||
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
public interface OwnerRepository {
|
||||
|
||||
@Query("SELECT DISTINCT owner FROM Owner owner left join owner.pets WHERE owner.lastName LIKE :1%")
|
||||
Object findByLastName(@Param("lastName") String lastName);
|
||||
}
|
||||
""";
|
||||
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA, source, Paths.get(jp.getLocationUri()).resolve("src/main/resource/my/package/OwnerRepository.java").toUri().toASCIIString());
|
||||
|
||||
editor.assertDocumentHighlights(":1", new DocumentHighlight(editor.rangeOf("String lastName", "lastName"), DocumentHighlightKind.Write));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void noOrdinalMatch() throws Exception {
|
||||
String source = """
|
||||
package my.package
|
||||
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
public interface OwnerRepository {
|
||||
|
||||
@Query("SELECT DISTINCT owner FROM Owner owner left join owner.pets WHERE owner.lastName LIKE :2%")
|
||||
Object findByLastName(@Param("lastName") String lastName);
|
||||
}
|
||||
""";
|
||||
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA, source, Paths.get(jp.getLocationUri()).resolve("src/main/resource/my/package/OwnerRepository.java").toUri().toASCIIString());
|
||||
|
||||
editor.assertDocumentHighlights(":1");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void noParameterNameMatch() throws Exception {
|
||||
String source = """
|
||||
package my.package
|
||||
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
public interface OwnerRepository {
|
||||
|
||||
@Query("SELECT DISTINCT owner FROM Owner owner left join owner.pets WHERE owner.lastName LIKE :name%")
|
||||
Object findByLastName(@Param("lastName") String lastName);
|
||||
}
|
||||
""";
|
||||
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA, source, Paths.get(jp.getLocationUri()).resolve("src/main/resource/my/package/OwnerRepository.java").toUri().toASCIIString());
|
||||
|
||||
editor.assertDocumentHighlights(":name");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -28,9 +28,7 @@ import java.util.Optional;
|
||||
import org.eclipse.lsp4j.Command;
|
||||
import org.eclipse.lsp4j.InlayHint;
|
||||
import org.eclipse.lsp4j.InlayHintLabelPart;
|
||||
import org.eclipse.lsp4j.InlayHintParams;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SpringProjectsProvider;
|
||||
@@ -79,7 +77,7 @@ public class PomInlayHintHandlerTest {
|
||||
|
||||
PomInlayHintHandler inlayHanlder = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
|
||||
|
||||
List<InlayHint> hints = inlayHanlder.handle(mock(CancelChecker.class), new InlayHintParams(new TextDocumentIdentifier(doc.getUri()), doc.toRange(0, doc.getLength())));
|
||||
List<InlayHint> hints = inlayHanlder.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
|
||||
|
||||
assertEquals(1, hints.size());
|
||||
|
||||
@@ -131,7 +129,7 @@ public class PomInlayHintHandlerTest {
|
||||
|
||||
PomInlayHintHandler inlayHanlder = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
|
||||
|
||||
List<InlayHint> hints = inlayHanlder.handle(mock(CancelChecker.class), new InlayHintParams(new TextDocumentIdentifier(doc.getUri()), doc.toRange(0, doc.getLength())));
|
||||
List<InlayHint> hints = inlayHanlder.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
|
||||
|
||||
assertEquals(0, hints.size());
|
||||
|
||||
@@ -169,7 +167,7 @@ public class PomInlayHintHandlerTest {
|
||||
|
||||
PomInlayHintHandler inlayHanlder = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
|
||||
|
||||
List<InlayHint> hints = inlayHanlder.handle(mock(CancelChecker.class), new InlayHintParams(new TextDocumentIdentifier(doc.getUri()), doc.toRange(0, doc.getLength())));
|
||||
List<InlayHint> hints = inlayHanlder.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
|
||||
|
||||
assertEquals(1, hints.size());
|
||||
|
||||
@@ -225,7 +223,7 @@ public class PomInlayHintHandlerTest {
|
||||
|
||||
PomInlayHintHandler inlayHanlder = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
|
||||
|
||||
List<InlayHint> hints = inlayHanlder.handle(mock(CancelChecker.class), new InlayHintParams(new TextDocumentIdentifier(doc.getUri()), doc.toRange(0, doc.getLength())));
|
||||
List<InlayHint> hints = inlayHanlder.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
|
||||
|
||||
assertEquals(0, hints.size());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user