Adjustments to AOT data query navigation, CodeLens

This commit is contained in:
aboyko
2025-05-08 19:43:18 -04:00
parent 5c50917a96
commit 21b26830eb
11 changed files with 136 additions and 60 deletions

View File

@@ -631,6 +631,14 @@ public class Editor {
.map(cl -> "'%s'".formatted(cl.getCommand().getTitle())).collect(Collectors.joining(", ")), codeLensText));
}
}
public List<CodeLens> getCodeLenses(String over, int occurrence) throws Exception {
int offset = getHoverPosition(over, occurrence);
return harness.getCodeLenses(doc).stream()
.filter(cl -> doc.toOffset(cl.getRange().getStart()) <= offset
&& doc.toOffset(cl.getRange().getEnd()) >= offset)
.collect(Collectors.toList());
}
public void assertLiveCodeLensContains(String codeLensOver, int occurrence, String snippet) throws Exception {
int cmPosition = getHoverPosition(codeLensOver, occurrence);

View File

@@ -420,7 +420,7 @@ public class BootLanguageServerBootApp {
new NamedDefinitionProvider(springIndex),
new DataQueryParameterDefinitionProvider(server.getTextDocumentService(), qurySemanticTokens),
new SpelDefinitionProvider(springIndex, cuCache),
new GenAotQueryMethodDefinitionProvider(cuCache, server.getTextDocumentService())));
new GenAotQueryMethodDefinitionProvider(server, cuCache, projectFinder)));
}
@Bean

View File

@@ -64,6 +64,8 @@ import com.google.gson.JsonElement;
@Component
public class BootLanguageServerInitializer implements InitializingBean {
public static final String CMD_SHOW_DOC = "sts/show/document";
@Autowired SimpleLanguageServer server;
@Autowired BootLanguageServerParams params;
@Autowired SourceLinks sourceLinks;
@@ -165,7 +167,7 @@ public class BootLanguageServerInitializer implements InitializingBean {
startListening();
server.onCommand("sts/show/document", p -> {
server.onCommand(CMD_SHOW_DOC, p -> {
ShowDocumentParams showDocParams = new Gson().fromJson((JsonElement)p.getArguments().get(0), ShowDocumentParams.class);
return server.getClient().showDocument(showDocParams).thenApply(r -> {
if (!r.isSuccess()) {

View File

@@ -20,17 +20,17 @@ import java.util.stream.Collectors;
import org.apache.commons.text.StringEscapeUtils;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.lsp4j.CodeLens;
import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
import org.springframework.ide.vscode.boot.java.handlers.CodeLensProvider;
import org.springframework.ide.vscode.boot.java.rewrite.RewriteRefactorings;
import org.springframework.ide.vscode.commons.java.IJavaProject;
@@ -46,7 +46,7 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
*/
public class DataRepositoryAotMetadataCodeLensProvider implements CodeLensProvider {
private static final String COVERT_TO_QUERY_LABEL = "Add @Query";
private static final String COVERT_TO_QUERY_LABEL = "Turn into @Query";
private static final Logger log = LoggerFactory.getLogger(DataRepositoryAotMetadataCodeLensProvider.class);
@@ -71,23 +71,12 @@ public class DataRepositoryAotMetadataCodeLensProvider implements CodeLensProvid
});
}
static boolean isDataQuaryNonAnnotatedMethodCandidate(IMethodBinding methodBinding) {
static boolean isValidMethodBinding(IMethodBinding methodBinding) {
if (methodBinding == null || methodBinding.getDeclaringClass() == null
|| methodBinding.getMethodDeclaration() == null
|| methodBinding.getDeclaringClass().getBinaryName() == null
|| methodBinding.getMethodDeclaration().toString() == null) {
|| methodBinding.getDeclaringClass().getBinaryName() == null) {
return false;
}
// Don't show CodeLens if annotated with `@Query` or `@NativeQuery`
for (IAnnotationBinding a : methodBinding.getAnnotations()) {
ITypeBinding t = a.getAnnotationType();
if (t != null
&& (Annotations.DATA_JPA_QUERY.equals(t.getQualifiedName()) || Annotations.DATA_JPA_NATIVE_QUERY.equals(t.getQualifiedName()))) {
return false;
}
}
return true;
}
@@ -115,7 +104,7 @@ public class DataRepositoryAotMetadataCodeLensProvider implements CodeLensProvid
IMethodBinding methodBinding = node.resolveBinding();
if (isDataQuaryNonAnnotatedMethodCandidate(methodBinding)) {
if (isValidMethodBinding(methodBinding)) {
cancelToken.checkCanceled();
getDataQuery(repositoryMetadataService, project, methodBinding)
.map(queryStatement -> createCodeLenses(node, document, queryStatement))
@@ -127,12 +116,30 @@ public class DataRepositoryAotMetadataCodeLensProvider implements CodeLensProvid
List<CodeLens> codeLenses = new ArrayList<>(2);
try {
IMethodBinding mb = node.resolveBinding();
Range range = document.toRange(node.getName().getStartPosition(), node.getName().getLength());
Command queryTitle = new Command();
queryTitle.setTitle(queryStatement);
codeLenses.add(new CodeLens(range, queryTitle, null));
if (mb != null) {
codeLenses.add(new CodeLens(range, refactorings.createFixCommand(COVERT_TO_QUERY_LABEL, createFixDescriptor(mb, document.getUri(), queryStatement)), null));
Position startPos = document.toPosition(node.getStartPosition());
Position endPos = document.toPosition(node.getName().getStartPosition() + node.getName().getLength());
Range range = new Range(startPos, endPos);
AnnotationHierarchies hierarchyAnnot = AnnotationHierarchies.get(node);
if (mb != null && hierarchyAnnot != null) {
boolean isQueryAnnotated = hierarchyAnnot.isAnnotatedWith(mb, Annotations.DATA_JPA_QUERY);
if (!isQueryAnnotated) {
codeLenses.add(new CodeLens(range, refactorings.createFixCommand(COVERT_TO_QUERY_LABEL, createFixDescriptor(mb, document.getUri(), queryStatement)), null));
}
Command impl = new Command("Implementation", GenAotQueryMethodDefinitionProvider.CMD_NAVIGATE_TO_IMPL, List.of(new GenAotQueryMethodDefinitionProvider.GoToImplParams(
document.getId(),
mb.getDeclaringClass().getQualifiedName(),
mb.getName(),
Arrays.stream(mb.getParameterTypes()).map(p -> p.getQualifiedName()).toArray(String[]::new),
null
)));
codeLenses.add(new CodeLens(range, impl, null));
if (!isQueryAnnotated) {
Command queryTitle = new Command();
queryTitle.setTitle(queryStatement);
codeLenses.add(new CodeLens(range, queryTitle, null));
}
}
} catch (BadLocationException e) {
log.error("bad location while calculating code lens for data repository query method", e);

View File

@@ -22,7 +22,9 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
@@ -35,6 +37,7 @@ import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.ShowDocumentParams;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.slf4j.Logger;
@@ -46,19 +49,29 @@ import org.springframework.ide.vscode.commons.Version;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
public class GenAotQueryMethodDefinitionProvider implements IJavaDefinitionProvider {
private static Logger log = LoggerFactory.getLogger(GenAotQueryMethodDefinitionProvider.class);
public static final String CMD_NAVIGATE_TO_IMPL = "sts/boot/open-data-query-method-aot-definition";
private final CompilationUnitCache cuCache;
private final SimpleTextDocumentService docService;
private final JavaProjectFinder projectFinder;
public GenAotQueryMethodDefinitionProvider(CompilationUnitCache cuCache, SimpleTextDocumentService docService) {
public GenAotQueryMethodDefinitionProvider(SimpleLanguageServer server, CompilationUnitCache cuCache, JavaProjectFinder projectFinder) {
this.cuCache = cuCache;
this.docService = docService;
this.docService = server.getTextDocumentService();
this.projectFinder = projectFinder;
registerCommands(server);
}
@Override
@@ -73,17 +86,29 @@ public class GenAotQueryMethodDefinitionProvider implements IJavaDefinitionProvi
&& methodBinding.getDeclaringClass() != null
&& ASTUtils.isAnyTypeInHierarchy(methodBinding.getDeclaringClass(),
List.of(Constants.REPOSITORY_TYPE))) {
String genRepoFqn = methodBinding.getDeclaringClass().getQualifiedName() + "Impl__Aot";
Path relativeGenSourcePath = Paths.get("%s.java".formatted(genRepoFqn.replace('.', '/')));
List<LocationLink> defs = findInSourceFolder(project, relativeGenSourcePath, docId, md, methodBinding, genRepoFqn);
return defs.isEmpty() ? findInBuildFolder(project, relativeGenSourcePath, docId, md, methodBinding, genRepoFqn) : defs;
try {
Range originRange = docService.getLatestSnapshot(docId.getUri()).toRange(md.getName().getStartPosition(), md.getName().getLength());
GoToImplParams params = new GoToImplParams(docId, methodBinding.getDeclaringClass().getQualifiedName(), methodBinding.getName(), Arrays.stream(methodBinding.getParameterTypes()).map(b -> b.getQualifiedName()).toArray(String[]::new), originRange);
return findDefinitions(project, params);
} catch (BadLocationException e) {
log.error("", e);
}
}
}
}
return List.of();
}
private List<LocationLink> getLocationInGenFile(IJavaProject project, TextDocumentIdentifier docId, MethodDeclaration md, IMethodBinding methodBinding, Path genRepoSourcePath, String genRepoFqn) {
private List<LocationLink> findDefinitions(IJavaProject project, GoToImplParams implParams) {
String genRepoFqn = implParams.repoFqName() + "Impl__Aot";
Path relativeGenSourcePath = Paths.get("%s.java".formatted(genRepoFqn.replace('.', '/')));
List<LocationLink> defs = findInSourceFolder(project, relativeGenSourcePath, genRepoFqn, implParams);
return defs.isEmpty() ? findInBuildFolder(project, relativeGenSourcePath, genRepoFqn, implParams) : defs;
}
private List<LocationLink> getLocationInGenFile(IJavaProject project, Path genRepoSourcePath, String genRepoFqn, GoToImplParams params) {
if (Files.exists(genRepoSourcePath)) {
URI genUri = genRepoSourcePath.toUri();
return cuCache.withCompilationUnit(project, genUri, genCu -> {
@@ -94,21 +119,18 @@ public class GenAotQueryMethodDefinitionProvider implements IJavaDefinitionProvi
public boolean visit(MethodDeclaration node) {
IMethodBinding genBinding = node.resolveBinding();
if (genBinding != null
&& genBinding.getName().equals(methodBinding.getName())
&& Arrays.equals(Arrays.stream(genBinding.getParameterTypes()).map(b -> b.getQualifiedName()).toArray(), Arrays.stream(methodBinding.getParameterTypes()).map(b -> b.getQualifiedName()).toArray() )
&& genBinding.getName().equals(params.queryMethodName())
&& Arrays.equals(Arrays.stream(genBinding.getParameterTypes()).map(b -> b.getQualifiedName()).toArray(), params.paramTypes)
&& genRepoFqn.equals(genBinding.getDeclaringClass().getQualifiedName())) {
LocationLink ll = new LocationLink();
ll.setTargetUri(genUri.toASCIIString());
try {
ll.setOriginSelectionRange(docService.getLatestSnapshot(docId.getUri()).toRange(md.getName().getStartPosition(), md.getName().getLength()));
} catch (BadLocationException e) {
log.error("", e);
}
ll.setOriginSelectionRange(params.originSelection());
SimpleName genName = node.getName();
int startLine = genCu.getLineNumber(genName.getStartPosition());
Position targetStartPosition = new Position(startLine, genName.getStartPosition() - genCu.getPosition(startLine, 0));
// LSP line are 0-based hence -1 from line number when building LSP Range/Position
Position targetStartPosition = new Position(startLine - 1, genName.getStartPosition() - genCu.getPosition(startLine, 0));
int endLine = genCu.getLineNumber(genName.getStartPosition() + genName.getLength());
Position targetEndPosition = new Position(endLine, genName.getStartPosition() + genName.getLength() - genCu.getPosition(endLine, 0));
Position targetEndPosition = new Position(endLine - 1, genName.getStartPosition() + genName.getLength() - genCu.getPosition(endLine, 0));
Range targetRange = new Range(targetStartPosition, targetEndPosition);
ll.setTargetRange(targetRange);
ll.setTargetSelectionRange(targetRange);
@@ -124,15 +146,15 @@ public class GenAotQueryMethodDefinitionProvider implements IJavaDefinitionProvi
return List.of();
}
private List<LocationLink> findInSourceFolder(IJavaProject project, Path relativeGenSourcePath, TextDocumentIdentifier docId, MethodDeclaration md, IMethodBinding methodBinding, String genRepoFqn) {
private List<LocationLink> findInSourceFolder(IJavaProject project, Path relativeGenSourcePath, String genRepoFqn, GoToImplParams params) {
for (File f : IClasspathUtil.getSourceFolders(project.getClasspath()).collect(Collectors.toSet())) {
Path genRepoSourcePath = f.toPath().resolve(relativeGenSourcePath);
return getLocationInGenFile(project, docId, md, methodBinding, genRepoSourcePath, genRepoFqn);
return getLocationInGenFile(project, genRepoSourcePath, genRepoFqn, params);
}
return List.of();
}
private List<LocationLink> findInBuildFolder(IJavaProject project, Path relativeGenSourcePath, TextDocumentIdentifier docId, MethodDeclaration md, IMethodBinding methodBinding, String genRepoFqn) {
private List<LocationLink> findInBuildFolder(IJavaProject project, Path relativeGenSourcePath, String genRepoFqn, GoToImplParams params) {
Path buildDirRelativePath = null;
Path projectPath = Paths.get(project.getLocationUri());
Set<Path> outputFolders = IClasspathUtil.getOutputFolders(project.getClasspath()).map(f -> f.toPath()).collect(Collectors.toSet());
@@ -182,7 +204,30 @@ public class GenAotQueryMethodDefinitionProvider implements IJavaDefinitionProvi
} catch (IOException e) {
log.error("", e);
}
return genSourceFilePathRef.get() == null ? List.of() : getLocationInGenFile(project, docId, md, methodBinding, genSourceFilePathRef.get(), genRepoFqn);
return genSourceFilePathRef.get() == null ? List.of() : getLocationInGenFile(project, genSourceFilePathRef.get(), genRepoFqn, params);
}
private void registerCommands(SimpleLanguageServer server) {
server.onCommand(CMD_NAVIGATE_TO_IMPL, params -> {
return CompletableFuture.supplyAsync(() -> {
GoToImplParams implParams = new Gson().fromJson((JsonElement) params.getArguments().get(0), GoToImplParams.class);
Optional<IJavaProject> project = projectFinder.find(implParams.docId());
if (project.isEmpty()) {
return List.<LocationLink>of();
}
return findDefinitions(project.get(), implParams);
}).thenCompose(links -> {
if (links.isEmpty()) {
return CompletableFuture.completedFuture(null);
} else {
ShowDocumentParams showDocParams = new ShowDocumentParams(links.get(0).getTargetUri());
showDocParams.setSelection(links.get(0).getTargetRange());
return server.getClient().showDocument(showDocParams);
}
});
});
}
public record GoToImplParams(TextDocumentIdentifier docId, String repoFqName, String queryMethodName, String[] paramTypes, Range originSelection) {}
}

View File

@@ -19,6 +19,8 @@ import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.CodeActionKind;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
import org.springframework.ide.vscode.boot.java.codeaction.JdtAstCodeActionProvider;
import org.springframework.ide.vscode.boot.java.rewrite.RewriteRefactorings;
import org.springframework.ide.vscode.commons.Version;
@@ -30,7 +32,7 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
public class QueryMethodCodeActionProvider implements JdtAstCodeActionProvider {
private static final String TITLE = "Convert into `@Query`";
private static final String TITLE = "Add `@Query`";
private final DataRepositoryAotMetadataService repositoryMetadataService;
private final RewriteRefactorings refactorings;
@@ -55,11 +57,12 @@ public class QueryMethodCodeActionProvider implements JdtAstCodeActionProvider {
public boolean visit(MethodDeclaration node) {
cancelToken.checkCanceled();
if (node.getStartPosition() <= region.getStart() && node.getStartPosition() + node.getLength() >= region.getEnd()) {
int offset = node.getName().getStartPosition();
int length = node.getName().getLength();
if (offset <= region.getStart() && offset + length >= region.getEnd()) {
int start = node.getStartPosition();
int end = node.getName().getStartPosition() + node.getName().getLength();
if (start <= region.getStart() && end >= region.getEnd()) {
IMethodBinding binding = node.resolveBinding();
if (DataRepositoryAotMetadataCodeLensProvider.isDataQuaryNonAnnotatedMethodCandidate(binding)) {
AnnotationHierarchies hierarchyAnnot = AnnotationHierarchies.get(node);
if (hierarchyAnnot != null && !hierarchyAnnot.isAnnotatedWith(binding, Annotations.DATA_JPA_QUERY)) {
DataRepositoryAotMetadataCodeLensProvider.getDataQuery(repositoryMetadataService, project, binding)
.map(query -> createCodeAction(binding, docURI, query)).ifPresent(collector::accept);
}

View File

@@ -19,6 +19,7 @@ import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.ShowDocumentParams;
import org.springframework.ide.vscode.boot.app.BootLanguageServerInitializer;
import org.springframework.ide.vscode.boot.validation.generations.json.Generation;
import org.springframework.ide.vscode.boot.validation.generations.json.ResolvedSpringProject;
import org.springframework.ide.vscode.boot.validation.generations.preferences.VersionValidationProblemType;
@@ -148,7 +149,7 @@ public class GenerationsValidator extends AbstractDiagnosticValidator {
showDocumentParams.setExternal(true);
showDocumentParams.setTakeFocus(true);
showDocumentParams.setSelection(new Range());
commercialSupportLink.setCommand(new Command("Get commercial Spring Boot support via Tanzu Spring Runtime", "sts/show/document",
commercialSupportLink.setCommand(new Command("Get commercial Spring Boot support via Tanzu Spring Runtime", BootLanguageServerInitializer.CMD_SHOW_DOC,
ImmutableList.of(showDocumentParams)));
return commercialSupportLink;
}

View File

@@ -21,6 +21,7 @@ import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.ShowDocumentParams;
import org.springframework.ide.vscode.boot.app.BootLanguageServerInitializer;
import org.springframework.ide.vscode.boot.java.rewrite.SpringBootUpgrade;
import org.springframework.ide.vscode.boot.validation.generations.preferences.VersionValidationProblemType;
import org.springframework.ide.vscode.commons.Version;
@@ -157,7 +158,7 @@ public class UpdateBootVersion extends AbstractDiagnosticValidator {
showDocumentParams.setExternal(true);
showDocumentParams.setTakeFocus(true);
showDocumentParams.setSelection(new Range());
releaseNoteLink.setCommand(new Command("Release Notes for Spring Boot " + version.toString(), "sts/show/document",
releaseNoteLink.setCommand(new Command("Release Notes for Spring Boot " + version.toString(), BootLanguageServerInitializer.CMD_SHOW_DOC,
ImmutableList.of(showDocumentParams)));
return releaseNoteLink;
}

View File

@@ -10,13 +10,17 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.data.test;
import static org.junit.Assert.assertEquals;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.lsp4j.CodeLens;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -64,8 +68,10 @@ public class DataRepositoryAotMetadataCodeLensProviderTest {
.resolve("src/main/java/example/springdata/aot/UserRepository.java");
Editor editor = harness.newEditor(LanguageId.JAVA, new String(Files.readAllBytes(filePath), StandardCharsets.UTF_8), filePath.toUri().toASCIIString());
editor.assertCodeLens("findUserByUsername", 1, "SELECT u FROM example.springdata.aot.User u WHERE u.username = :username");
editor.assertCodeLens("findUserByUsername", 1, "Add @Query");
List<CodeLens> cls = editor.getCodeLenses("findUserByUsername", 1);
assertEquals("Turn into @Query", cls.get(0).getCommand().getTitle());
assertEquals("Implementation", cls.get(1).getCommand().getTitle());
assertEquals("SELECT u FROM example.springdata.aot.User u WHERE u.username = :username", cls.get(2).getCommand().getTitle());
}
@Test
@@ -74,6 +80,9 @@ public class DataRepositoryAotMetadataCodeLensProviderTest {
.resolve("src/main/java/example/springdata/aot/UserRepository.java");
Editor editor = harness.newEditor(LanguageId.JAVA, new String(Files.readAllBytes(filePath), StandardCharsets.UTF_8), filePath.toUri().toASCIIString());
editor.assertCodeLens("usersWithUsernamesStartingWith", 1, null);
List<CodeLens> cls = editor.getCodeLenses("usersWithUsernamesStartingWith", 1);
assertEquals(1, cls.size());
assertEquals("Implementation", cls.get(0).getCommand().getTitle());
assertEquals(1, cls.get(0).getCommand().getArguments().size());
}
}

View File

@@ -73,8 +73,8 @@ public class GenAotQueryMethodDefinitionProviderTest {
.resolve("target/spring-aot/main/sources/example/springdata/aot/UserRepositoryImpl__Aot.java").toUri()
.toASCIIString());
ll.setOriginSelectionRange(new Range(new Position(43, 15), new Position(43, 61)));
ll.setTargetRange(new Range(new Position(145, 20), new Position(145, 66)));
ll.setTargetSelectionRange(new Range(new Position(145, 20), new Position(145, 66)));
ll.setTargetRange(new Range(new Position(144, 20), new Position(144, 66)));
ll.setTargetSelectionRange(new Range(new Position(144, 20), new Position(144, 66)));
editor.assertLinkTargets("findUserByLastnameStartingWith", List.of(ll));
}
@@ -89,8 +89,8 @@ public class GenAotQueryMethodDefinitionProviderTest {
.resolve("target/spring-aot/main/sources/example/springdata/aot/UserRepositoryImpl__Aot.java").toUri()
.toASCIIString());
ll.setOriginSelectionRange(new Range(new Position(54, 15), new Position(54, 45)));
ll.setTargetRange(new Range(new Position(191, 20), new Position(191, 50)));
ll.setTargetSelectionRange(new Range(new Position(191, 20), new Position(191, 50)));
ll.setTargetRange(new Range(new Position(190, 20), new Position(190, 50)));
ll.setTargetSelectionRange(new Range(new Position(190, 20), new Position(190, 50)));
editor.assertLinkTargets("usersWithUsernamesStartingWith", List.of(ll));
}

View File

@@ -79,7 +79,7 @@ public class QueryMethodCodeActionProviderTest {
List<CodeAction> codeActions = editor.getCodeActions("findUserByLastnameStartingWith", 1);
assertEquals(1, codeActions.size());
CodeAction ca = codeActions.get(0);
assertEquals("Convert into `@Query`", ca.getLabel());
assertEquals("Add `@Query`", ca.getLabel());
Command cmd = ca.getCommand();
assertEquals(RewriteRefactorings.REWRITE_RECIPE_QUICKFIX, cmd.getArguments().get(0));
WorkspaceEdit edit = refactorings.createEdit((JsonElement) cmd.getArguments().get(1)).get(5, TimeUnit.SECONDS);