Skip to content

Commit

Permalink
Bean completion case of the same name field
Browse files Browse the repository at this point in the history
  • Loading branch information
BoykoAlex committed Feb 28, 2025
1 parent d595f03 commit b0d42d1
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public class BeanCompletionProposal implements ICompletionProposalWithScore {
private IDocument doc;
private String beanId;
private String beanType;
private String fieldName;
private String className;
private RewriteRefactorings rewriteRefactorings;
private double score;
Expand All @@ -64,12 +65,13 @@ public class BeanCompletionProposal implements ICompletionProposalWithScore {
private DocumentEdits edits;

public BeanCompletionProposal(ASTNode node, int offset, IDocument doc, String beanId, String beanType,
String className, RewriteRefactorings rewriteRefactorings) {
String fieldName, String className, RewriteRefactorings rewriteRefactorings) {
this.node = node;
this.offset = offset;
this.doc = doc;
this.beanId = beanId;
this.beanType = beanType;
this.fieldName = fieldName;
this.className = className;
this.rewriteRefactorings = rewriteRefactorings;
this.prefix = computePrefix();
Expand Down Expand Up @@ -130,19 +132,19 @@ private DocumentEdits computeEdit() {
DocumentEdits edits = new DocumentEdits(doc, false);
if (isInsideConstructor(node)) {
if (node instanceof Block) {
edits.insert(offset, "this.%s = %s;".formatted(beanId, beanId));
edits.insert(offset, "this.%s = %s;".formatted(fieldName, fieldName));
} else {
if (node.getParent() instanceof Assignment || node.getParent() instanceof FieldAccess) {
edits.replace(offset - prefix.length(), offset, "%s = %s;".formatted(beanId, beanId));
edits.replace(offset - prefix.length(), offset, "%s = %s;".formatted(fieldName, fieldName));
} else {
edits.replace(offset - prefix.length(), offset, "this.%s = %s;".formatted(beanId, beanId));
edits.replace(offset - prefix.length(), offset, "this.%s = %s;".formatted(fieldName, fieldName));
}
}
} else {
if (node instanceof Block) {
edits.insert(offset, beanId);
edits.insert(offset, fieldName);
} else {
edits.replace(offset - prefix.length(), offset, beanId);
edits.replace(offset - prefix.length(), offset, fieldName);
}
}
return edits;
Expand Down Expand Up @@ -176,7 +178,7 @@ public Renderable getDocumentation() {
public Optional<Command> getCommand() {
FixDescriptor f = new FixDescriptor(InjectBeanCompletionRecipe.class.getName(), List.of(this.doc.getUri()),
"Inject bean completions")
.withParameters(Map.of("fullyQualifiedName", beanType, "fieldName", beanId, "classFqName", className))
.withParameters(Map.of("fullyQualifiedName", beanType, "fieldName", fieldName, "classFqName", className))
.withRecipeScope(RecipeScope.NODE);
return Optional.of(rewriteRefactorings.createFixCommand("Inject bean '%s'".formatted(beanId), f));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,18 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.beans;

import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.ThisExpression;
Expand Down Expand Up @@ -99,23 +98,28 @@ public void provideCompletions(ASTNode node, int offset, TextDocument doc,
String className = getFullyQualifiedName(topLevelClass);
Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
ITypeBinding topLevelBeanType = topLevelClass.resolveBinding();
Set<String> declaredFiledsTypes = Arrays.stream(topLevelBeanType.getDeclaredFields())
.map(vd -> vd.getType())
.filter(Objects::nonNull)
.map(t -> t.getQualifiedName())
.collect(Collectors.toSet());
Set<String> fieldTypes = new HashSet<>();
Set<String> fieldNames = new HashSet<>();
for (IVariableBinding vd : topLevelBeanType.getDeclaredFields()) {
fieldNames.add(vd.getName());
fieldTypes.add(vd.getType().getQualifiedName());
}
for (Bean bean : beans) {
// If current class is a bean - ignore it
if (className.equals(bean.getType())) {
continue;
}
// Filter out beans already injected into this class
if (declaredFiledsTypes.contains(bean.getType())) {
if (fieldTypes.contains(bean.getType())) {
continue;
}


String fieldName = bean.getName();
for (int i = 0; i < Integer.MAX_VALUE && fieldNames.contains(fieldName); i++, fieldName = "%s_%d".formatted(bean.getName(), i)) {
// nothing
}
BeanCompletionProposal proposal = new BeanCompletionProposal(node, offset, doc, bean.getName(),
bean.getType(), className, rewriteRefactorings);
bean.getType(), fieldName, className, rewriteRefactorings);

if (proposal.getScore() > 0) {
completions.add(proposal);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,84 @@ public void test() {
""");
}

@Test
public void sameNameFieldExists_Constructor() throws Exception {
String content = """
package org.sample.test;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestBeanCompletionClass {
String ownerRepository;
public TestBeanCompletionClass(String ownerRepository) {
this.ownerRepository = ownerRepository;
ow<*>
}
}
""";


assertCompletions(content, new String[] {"ownerRepository", "ownerService"}, 0,
"""
package org.sample.test;
import org.springframework.samples.petclinic.owner.OwnerRepository;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestBeanCompletionClass {
private final OwnerRepository ownerRepository_1;
String ownerRepository;
public TestBeanCompletionClass(String ownerRepository, OwnerRepository ownerRepository_1) {
this.ownerRepository = ownerRepository;
this.ownerRepository_1 = ownerRepository_1;<*>
}
}
""");
}

@Test
public void sameNameFieldExists_Method() throws Exception {
String content = """
package org.sample.test;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestBeanCompletionClass {
String ownerRepository;
public void test() {
ow<*>
}
}
""";


assertCompletions(content, new String[] {"ownerRepository", "ownerService"}, 0,
"""
package org.sample.test;
import org.springframework.samples.petclinic.owner.OwnerRepository;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestBeanCompletionClass {
private final OwnerRepository ownerRepository_1;
String ownerRepository;
TestBeanCompletionClass(OwnerRepository ownerRepository_1) {
this.ownerRepository_1 = ownerRepository_1;
}
public void test() {
ownerRepository_1<*>
}
}
""");
}

@Test
public void beforeStatementStartingWithThisAndPrefix() throws Exception {
String content = """
Expand Down

0 comments on commit b0d42d1

Please sign in to comment.