diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java index ffa21afd2..95afe2e8f 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java @@ -323,8 +323,8 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent specificProviders.put(Annotations.VALUE, new ValuePropertyReferencesProvider(projectFinder, index)); specificProviders.put(Annotations.CONDITIONAL_ON_PROPERTY, new ValuePropertyReferencesProvider(projectFinder, index)); specificProviders.put(Annotations.QUALIFIER, new QualifierReferencesProvider(index)); - specificProviders.put(Annotations.NAMED_JAKARTA, new NamedReferencesProvider(index, symbolIndex)); - specificProviders.put(Annotations.NAMED_JAVAX, new NamedReferencesProvider(index, symbolIndex)); + specificProviders.put(Annotations.NAMED_JAKARTA, new NamedReferencesProvider(index)); + specificProviders.put(Annotations.NAMED_JAVAX, new NamedReferencesProvider(index)); specificProviders.put(Annotations.PROFILE, new ProfileReferencesProvider(index)); List unspecificProviders = new ArrayList<>(); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/NamedReferencesProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/NamedReferencesProvider.java index fa2f0099e..f49693031 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/NamedReferencesProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/NamedReferencesProvider.java @@ -16,12 +16,13 @@ import java.util.stream.Stream; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Annotation; +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.StringLiteral; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.jsonrpc.CancelChecker; -import org.springframework.ide.vscode.boot.app.SpringSymbolIndex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.handlers.ReferenceProvider; @@ -35,12 +36,12 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument; */ public class NamedReferencesProvider implements ReferenceProvider { - private final SpringMetamodelIndex springIndex; - private final SpringSymbolIndex symbolIndex; + private static final Logger log = LoggerFactory.getLogger(NamedReferencesProvider.class); - public NamedReferencesProvider(SpringMetamodelIndex springIndex, SpringSymbolIndex symbolIndex) { + private final SpringMetamodelIndex springIndex; + + public NamedReferencesProvider(SpringMetamodelIndex springIndex) { this.springIndex = springIndex; - this.symbolIndex = symbolIndex; } @Override @@ -49,22 +50,22 @@ public class NamedReferencesProvider implements ReferenceProvider { cancelToken.checkCanceled(); try { + while (node != null && !(node.getParent() instanceof Annotation) && !(node.getParent() instanceof MemberValuePair)) { + node = node.getParent(); + } + // case: @Value("prefix<*>") - if (node instanceof StringLiteral && node.getParent() instanceof Annotation) { - if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) { - return provideReferences(project, ASTUtils.getLiteralValue((StringLiteral) node)); - } + if (node instanceof Expression expression && node.getParent() instanceof Annotation) { + return provideReferences(project, ASTUtils.getExpressionValueAsString(expression, v -> {})); } // case: @Value(value="prefix<*>") - else if (node instanceof StringLiteral && node.getParent() instanceof MemberValuePair + else if (node instanceof Expression expression && node.getParent() instanceof MemberValuePair && "value".equals(((MemberValuePair)node.getParent()).getName().toString())) { - if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) { - return provideReferences(project, ASTUtils.getLiteralValue((StringLiteral) node)); - } + return provideReferences(project, ASTUtils.getExpressionValueAsString(expression, v -> {})); } } catch (Exception e) { - e.printStackTrace(); + log.error("error finding references for named annotatio value", e); } return null; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ProfileReferencesProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ProfileReferencesProvider.java index ea2ac63e7..8ea2a8f54 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ProfileReferencesProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ProfileReferencesProvider.java @@ -17,11 +17,13 @@ import java.util.stream.Stream; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Annotation; import org.eclipse.jdt.core.dom.ArrayInitializer; +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.StringLiteral; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.jsonrpc.CancelChecker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.handlers.ReferenceProvider; @@ -35,6 +37,8 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument; */ public class ProfileReferencesProvider implements ReferenceProvider { + private static final Logger log = LoggerFactory.getLogger(ProfileReferencesProvider.class); + private final SpringMetamodelIndex springIndex; public ProfileReferencesProvider(SpringMetamodelIndex springIndex) { @@ -47,28 +51,29 @@ public class ProfileReferencesProvider implements ReferenceProvider { cancelToken.checkCanceled(); try { + while (node != null + && !(node.getParent() instanceof Annotation) + && !(node.getParent() instanceof MemberValuePair) + && !(node.getParent() instanceof ArrayInitializer)) { + node = node.getParent(); + } + // case: @Value("prefix<*>") - if (node instanceof StringLiteral && node.getParent() instanceof Annotation) { - if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) { - return provideReferences(project, ASTUtils.getLiteralValue((StringLiteral) node)); - } + if (node instanceof Expression expression && node.getParent() instanceof Annotation) { + return provideReferences(project, ASTUtils.getExpressionValueAsString(expression, v -> {})); } // case: @Value(value="prefix<*>") - else if (node instanceof StringLiteral && node.getParent() instanceof MemberValuePair + else if (node instanceof Expression expression && node.getParent() instanceof MemberValuePair && "value".equals(((MemberValuePair)node.getParent()).getName().toString())) { - if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) { - return provideReferences(project, ASTUtils.getLiteralValue((StringLiteral) node)); - } + return provideReferences(project, ASTUtils.getExpressionValueAsString(expression, v -> {})); } // case: @Qualifier({"prefix<*>"}) - else if (node instanceof StringLiteral && node.getParent() instanceof ArrayInitializer) { - if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) { - return provideReferences(project, ASTUtils.getLiteralValue((StringLiteral) node)); - } + else if (node instanceof Expression expression && node.getParent() instanceof ArrayInitializer) { + return provideReferences(project, ASTUtils.getExpressionValueAsString(expression, v -> {})); } } catch (Exception e) { - e.printStackTrace(); + log.error("error finding references for profile", e); } return null; diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/NamedReferencesProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/NamedReferencesProviderTest.java index e180a87c6..c2bfbf88b 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/NamedReferencesProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/NamedReferencesProviderTest.java @@ -120,6 +120,24 @@ public class NamedReferencesProviderTest { assertEquals(locationNamedAnnotation1, foundLocation); } + @Test + public void testNamedRefersToNamedBeanWithConcatenatedString() throws Exception { + Editor editor = harness.newEditor(LanguageId.JAVA, """ + package org.test; + + import jakarta.inject.Named; + + @Named("na" + "m<*>ed1") + public class TestDependsOnClass { + }""", tempJavaDocUri); + + List references = editor.getReferences(); + assertEquals(1, references.size()); + + Location foundLocation = references.get(0); + assertEquals(locationNamedAnnotation1, foundLocation); + } + @Test public void testNamedNotRefersToPureSpringBean() throws Exception { Editor editor = harness.newEditor(LanguageId.JAVA, """ diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/ProfileReferencesProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/ProfileReferencesProviderTest.java index 836fd1b42..a2f5a116c 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/ProfileReferencesProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/ProfileReferencesProviderTest.java @@ -95,6 +95,37 @@ public class ProfileReferencesProviderTest { assertTrue(references.contains(expectedLocation2)); } + @Test + public void testProfileRefersToOtherProfilesWithConcatenatedString() throws Exception { + String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString(); + + Editor editor = harness.newEditor(LanguageId.JAVA, """ + package org.test; + + import org.springframework.stereotype.Component; + import org.springframework.context.annotation.Profile; + + @Component + @Profile("pro" + "f<*>ile1") + public class TestDependsOnClass { + }""", tempJavaDocUri); + + List references = editor.getReferences(); + assertEquals(2, references.size()); + + String expectedDefinitionUri1 = directory.toPath().resolve("src/main/java/org/test/profiles/ProfilesClass1.java").toUri().toString(); + Location expectedLocation1 = new Location(expectedDefinitionUri1, + new Range(new Position(6, 9), new Position(6, 19))); + + assertTrue(references.contains(expectedLocation1)); + + String expectedDefinitionUri2 = directory.toPath().resolve("src/main/java/org/test/profiles/ProfilesClassWithArray.java").toUri().toString(); + Location expectedLocation2 = new Location(expectedDefinitionUri2, + new Range(new Position(6, 18), new Position(6, 28))); + + assertTrue(references.contains(expectedLocation2)); + } + @Test public void testProfileWithinArrayRefersToOtherProfiles() throws Exception { String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString();