diff --git a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java index cd428389b..6bf6e5778 100644 --- a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java +++ b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java @@ -43,6 +43,7 @@ import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.DocumentSymbol; import org.eclipse.lsp4j.Hover; import org.eclipse.lsp4j.InsertReplaceEdit; +import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.LocationLink; import org.eclipse.lsp4j.MarkedString; import org.eclipse.lsp4j.MarkupContent; @@ -571,6 +572,11 @@ public class Editor { }); return items; } + + public List getReferences() throws Exception { + List references = harness.getReferences(this.doc, this.getCursor()); + return references; + } public CompletionItem getFirstCompletion() throws Exception { return getCompletions().get(0); diff --git a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java index 6f2d5cfd0..55ed2b987 100644 --- a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java +++ b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java @@ -84,6 +84,7 @@ import org.eclipse.lsp4j.MessageParams; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.ReferenceParams; import org.eclipse.lsp4j.RegistrationParams; import org.eclipse.lsp4j.RenameFile; import org.eclipse.lsp4j.ResourceOperation; @@ -649,6 +650,15 @@ public class LanguageServerHarness { } } + public List getReferences(TextDocumentInfo doc, Position cursor) throws Exception { + ReferenceParams params = new ReferenceParams(); + params.setPosition(cursor); + params.setTextDocument(doc.getId()); + waitForReconcile(); + List references = getServer().getTextDocumentService().references(params).get(); + return references; + } + private void waitForReconcile() throws Exception { getServer().getAsync().waitForAll(); getServer().waitForReconcile(); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReferencesHandler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReferencesHandler.java index 24dd939f1..567b1e7cb 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReferencesHandler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReferencesHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2022 Pivotal, Inc. + * Copyright (c) 2017, 2024 Pivotal, 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 @@ -117,12 +117,13 @@ public class BootJavaReferencesHandler implements ReferencesHandler { private List provideReferencesForAnnotation(CancelChecker cancelToken, ASTNode node, int offset, TextDocument doc) { Annotation annotation = null; - while (node != null && !(node instanceof Annotation)) { - node = node.getParent(); + ASTNode annotationNode = node; + while (annotationNode != null && !(annotationNode instanceof Annotation)) { + annotationNode = annotationNode.getParent(); } - if (node != null) { - annotation = (Annotation) node; + if (annotationNode != null) { + annotation = (Annotation) annotationNode; ITypeBinding type = annotation.resolveTypeBinding(); if (type != null) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValuePropertyReferencesProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValuePropertyReferencesProvider.java index 1262a86f9..534ee3d51 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValuePropertyReferencesProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValuePropertyReferencesProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2023 Pivotal, Inc. + * Copyright (c) 2017, 2024 Pivotal, 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 diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/references/test/PropertyReferenceFinderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/references/test/ValuePropertyReferenceFinderTest.java similarity index 68% rename from headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/references/test/PropertyReferenceFinderTest.java rename to headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/references/test/ValuePropertyReferenceFinderTest.java index 7fb14aaba..13f600b1b 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/references/test/PropertyReferenceFinderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/references/test/ValuePropertyReferenceFinderTest.java @@ -13,26 +13,76 @@ package org.springframework.ide.vscode.boot.java.references.test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import java.io.File; import java.net.URI; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collection; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.TextDocumentIdentifier; import org.eclipse.lsp4j.WorkspaceFolder; +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.app.SpringSymbolIndex; +import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest; +import org.springframework.ide.vscode.boot.bootiful.SymbolProviderTestConf; +import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; +import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.value.ValuePropertyReferencesProvider; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.protocol.spring.Bean; +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; import com.google.common.collect.ImmutableList; /** * @author Martin Lippert */ -public class PropertyReferenceFinderTest { +@ExtendWith(SpringExtension.class) +@BootLanguageServerTest +@Import(SymbolProviderTestConf.class) +public class ValuePropertyReferenceFinderTest { - @Test + @Autowired private BootLanguageServerHarness harness; + @Autowired private JavaProjectFinder projectFinder; + @Autowired private SpringMetamodelIndex springIndex; + @Autowired private SpringSymbolIndex indexer; + + private File directory; + private IJavaProject project; + private Bean[] indexedBeans; + private String tempJavaDocUri; + private Bean bean1; + private Bean bean2; + + @BeforeEach + public void setup() throws Exception { + harness.intialize(null); + + directory = new File(ProjectsHarness.class.getResource("/test-projects/test-spring-indexing/").toURI()); + + String projectDir = directory.toURI().toString(); + project = projectFinder.find(new TextDocumentIdentifier(projectDir)).get(); + + tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString(); + + CompletableFuture initProject = indexer.waitOperation(); + initProject.get(5, TimeUnit.SECONDS); + } + + @Test void testFindReferenceAtBeginningPropFile() throws Exception { ValuePropertyReferencesProvider provider = new ValuePropertyReferencesProvider(null); @@ -165,4 +215,39 @@ public class PropertyReferenceFinderTest { assertEquals(3, location.getRange().getEnd().getLine()); assertEquals(6, location.getRange().getEnd().getCharacter()); } + + @Test + void testFindReferencesToPropertyFromValueAnnotation() throws Exception { + harness.getServer().getWorkspaceService().setWorkspaceFolders(List.of(new WorkspaceFolder(directory.toURI().toString()))); + + String completionLine = "@Value(\"${my.<*>prop}\")"; + + String editorContent = """ + package org.test; + + import + """ + + Annotations.VALUE + ";" + + """ + + @Component + """ + + completionLine + "\n" + + """ + public class TestDependsOnClass { + } + """; + + Editor editor = harness.newEditor(LanguageId.JAVA, editorContent, tempJavaDocUri); + List references = editor.getReferences(); + + assertEquals(1, references.size()); + + Location location = references.get(0); + assertEquals(directory.toPath().resolve("src/main/java/application.properties").toUri().toString(), location.getUri()); + assertEquals(0, location.getRange().getStart().getLine()); + assertEquals(0, location.getRange().getStart().getCharacter()); + assertEquals(0, location.getRange().getEnd().getLine()); + assertEquals(7, location.getRange().getEnd().getCharacter()); + } } diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/application.properties b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/application.properties new file mode 100644 index 000000000..a638741e6 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/application.properties @@ -0,0 +1 @@ +my.prop=test \ No newline at end of file