GH-1463: support for concatenated strings for more reference providers

This commit is contained in:
Martin Lippert
2025-02-10 18:11:15 +01:00
parent 4d767eb86d
commit f96b32bfc0
5 changed files with 86 additions and 31 deletions

View File

@@ -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<ReferenceProvider> unspecificProviders = new ArrayList<>();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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<? extends Location> 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, """

View File

@@ -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<? extends Location> 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();