GH-1261: extracted general annotation attribute content-assist mechanics, first steps towards a more re-usaeble implementation
This commit is contained in:
@@ -23,9 +23,10 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProcessor;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
|
||||
import org.springframework.ide.vscode.boot.java.beans.DependsOnCompletionProcessor;
|
||||
import org.springframework.ide.vscode.boot.java.beans.QualifierCompletionProcessor;
|
||||
import org.springframework.ide.vscode.boot.java.beans.QualifierCompletionProvider;
|
||||
import org.springframework.ide.vscode.boot.java.data.DataRepositoryCompletionProcessor;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaCompletionEngine;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider;
|
||||
@@ -111,12 +112,14 @@ public class BootJavaCompletionEngineConfigurer {
|
||||
|
||||
Map<String, CompletionProvider> providers = new HashMap<>();
|
||||
|
||||
providers.put(Annotations.SCOPE, new ScopeCompletionProcessor());
|
||||
providers.put(Annotations.VALUE, new ValueCompletionProcessor(javaProjectFinder, indexProvider, adHocProperties));
|
||||
providers.put(Annotations.DEPENDS_ON, new DependsOnCompletionProcessor(javaProjectFinder, springIndex));
|
||||
providers.put(Annotations.QUALIFIER, new QualifierCompletionProcessor(javaProjectFinder, springIndex));
|
||||
providers.put(Annotations.REPOSITORY, new DataRepositoryCompletionProcessor());
|
||||
|
||||
providers.put(Annotations.SCOPE, new AnnotationAttributeCompletionProcessor(javaProjectFinder, Map.of("value", new ScopeCompletionProcessor())));
|
||||
providers.put(Annotations.DEPENDS_ON, new AnnotationAttributeCompletionProcessor(javaProjectFinder, Map.of("value", new DependsOnCompletionProcessor(springIndex))));
|
||||
providers.put(Annotations.QUALIFIER, new AnnotationAttributeCompletionProcessor(javaProjectFinder, Map.of("value", new QualifierCompletionProvider(springIndex))));
|
||||
|
||||
|
||||
return new BootJavaCompletionEngine(cuCache, providers, snippetManager);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,18 +8,16 @@
|
||||
* Contributors:
|
||||
* Broadcom - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.beans;
|
||||
package org.springframework.ide.vscode.boot.java.annotations;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
@@ -28,28 +26,26 @@ import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.beans.QualifierCompletionProposal;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
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.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class QualifierCompletionProcessor implements CompletionProvider {
|
||||
|
||||
public class AnnotationAttributeCompletionProcessor implements CompletionProvider {
|
||||
|
||||
private final JavaProjectFinder projectFinder;
|
||||
private final SpringMetamodelIndex springIndex;
|
||||
private final Map<String, AnnotationAttributeCompletionProvider> completionProviders;
|
||||
|
||||
public QualifierCompletionProcessor(JavaProjectFinder projectFinder, SpringMetamodelIndex springIndex) {
|
||||
public AnnotationAttributeCompletionProcessor(JavaProjectFinder projectFinder, Map<String, AnnotationAttributeCompletionProvider> completionProviders) {
|
||||
this.projectFinder = projectFinder;
|
||||
this.springIndex = springIndex;
|
||||
this.completionProviders = completionProviders;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -67,7 +63,6 @@ public class QualifierCompletionProcessor implements CompletionProvider {
|
||||
// case: @Qualifier(<*>)
|
||||
if (node == annotation && doc.get(offset - 1, 2).endsWith("()")) {
|
||||
createCompletionProposals(project, doc, node, completions, offset, offset, "", (beanName) -> "\"" + beanName + "\"");
|
||||
|
||||
}
|
||||
// case: @Qualifier(prefix<*>)
|
||||
else if (node instanceof SimpleName && node.getParent() instanceof Annotation) {
|
||||
@@ -105,7 +100,41 @@ public class QualifierCompletionProcessor implements CompletionProvider {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create the concrete completion proposal
|
||||
*/
|
||||
private void createCompletionProposals(IJavaProject project, TextDocument doc, ASTNode node, Collection<ICompletionProposal> completions, int startOffset, int endOffset,
|
||||
String filterPrefix, Function<String, String> createReplacementText) {
|
||||
|
||||
Set<String> alreadyMentionedValues = alreadyMentionedValues(node);
|
||||
|
||||
AnnotationAttributeCompletionProvider completionProvider = this.completionProviders.get("value");
|
||||
if (completionProvider != null) {
|
||||
List<String> candidates = completionProvider.getCompletionCandidates(project);
|
||||
|
||||
List<String> filteredCandidates = candidates.stream()
|
||||
.filter(candidate -> candidate.toLowerCase().startsWith(filterPrefix.toLowerCase()))
|
||||
.filter(candidate -> !alreadyMentionedValues.contains(candidate))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
double score = filteredCandidates.size();
|
||||
for (String candidate : filteredCandidates) {
|
||||
|
||||
DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
edits.replace(startOffset, endOffset, createReplacementText.apply(candidate));
|
||||
|
||||
QualifierCompletionProposal proposal = new QualifierCompletionProposal(edits, candidate, candidate, null, score--);
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// internal computation of the right positions, prefixes, etc.
|
||||
//
|
||||
|
||||
private void computeProposalsForSimpleName(IJavaProject project, ASTNode node, Collection<ICompletionProposal> completions, int offset, TextDocument doc) {
|
||||
String prefix = identifyPropertyPrefix(node.toString(), offset - node.getStartPosition());
|
||||
|
||||
@@ -123,7 +152,7 @@ public class QualifierCompletionProcessor implements CompletionProvider {
|
||||
|
||||
String prefix = identifyPropertyPrefix(doc.get(node.getStartPosition() + 1, length), length);
|
||||
int startOffset = offset - prefix.length();
|
||||
int endOffset = offset;
|
||||
int endOffset = node.getStartPosition() + node.getLength() - 1;
|
||||
|
||||
createCompletionProposals(project, doc, node, completions, startOffset, endOffset, prefix, (beanName) -> beanName);
|
||||
}
|
||||
@@ -142,34 +171,6 @@ public class QualifierCompletionProcessor implements CompletionProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private void createCompletionProposals(IJavaProject project, TextDocument doc, ASTNode node, Collection<ICompletionProposal> completions, int startOffset, int endOffset,
|
||||
String filterPrefix, Function<String, String> createReplacementText) {
|
||||
|
||||
Set<String> mentionedQualifiers = alreadyMentionedValues(node);
|
||||
|
||||
Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
|
||||
Set<String> candidates = Stream.concat(
|
||||
findAllQualifiers(beans),
|
||||
Arrays.stream(beans).map(bean -> bean.getName()))
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
|
||||
List<String> filteredCandidates = candidates.stream()
|
||||
.filter(candidate -> candidate.toLowerCase().startsWith(filterPrefix.toLowerCase()))
|
||||
.filter(candidate -> !mentionedQualifiers.contains(candidate))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
||||
double score = filteredCandidates.size();
|
||||
for (String candidate : filteredCandidates) {
|
||||
|
||||
DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
edits.replace(startOffset, endOffset, createReplacementText.apply(candidate));
|
||||
|
||||
QualifierCompletionProposal proposal = new QualifierCompletionProposal(edits, candidate, candidate, null, score--);
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
|
||||
private String identifyPropertyPrefix(String nodeContent, int offset) {
|
||||
String result = nodeContent.substring(0, offset);
|
||||
|
||||
@@ -186,7 +187,7 @@ public class QualifierCompletionProcessor implements CompletionProvider {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Set<String> alreadyMentionedValues(ASTNode node) {
|
||||
protected Set<String> alreadyMentionedValues(ASTNode node) {
|
||||
Set<String> result = new HashSet<>();
|
||||
|
||||
ArrayInitializer arrayNode = null;
|
||||
@@ -213,29 +214,4 @@ public class QualifierCompletionProcessor implements CompletionProvider {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Stream<String> findAllQualifiers(Bean[] beans) {
|
||||
|
||||
Stream<String> qualifiersFromBeans = Arrays.stream(beans)
|
||||
// annotations from beans themselves
|
||||
.flatMap(bean -> Arrays.stream(bean.getAnnotations()))
|
||||
.filter(annotation -> Annotations.QUALIFIER.equals(annotation.getAnnotationType()))
|
||||
.filter(annotation -> annotation.getAttributes() != null && annotation.getAttributes().containsKey("value") && annotation.getAttributes().get("value").length == 1)
|
||||
.map(annotation -> annotation.getAttributes().get("value")[0]);
|
||||
|
||||
Stream<String> qualifiersFromInjectionPoints = Arrays.stream(beans)
|
||||
// annotations from beans themselves
|
||||
.filter(bean -> bean.getInjectionPoints() != null)
|
||||
.flatMap(bean -> Arrays.stream(bean.getInjectionPoints()))
|
||||
.filter(injectionPoint -> injectionPoint.getAnnotations() != null)
|
||||
.flatMap(injectionPoint -> Arrays.stream(injectionPoint.getAnnotations()))
|
||||
.filter(annotation -> Annotations.QUALIFIER.equals(annotation.getAnnotationType()))
|
||||
.filter(annotation -> annotation.getAttributes() != null && annotation.getAttributes().containsKey("value") && annotation.getAttributes().get("value").length == 1)
|
||||
.map(annotation -> annotation.getAttributes().get("value")[0]);
|
||||
|
||||
return Stream.concat(qualifiersFromBeans, qualifiersFromInjectionPoints);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2024 Broadcom
|
||||
* 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
* Broadcom - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.requestmapping;
|
||||
package org.springframework.ide.vscode.boot.java.annotations;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class RequestMappingCompletionProcessor {
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
|
||||
public interface AnnotationAttributeCompletionProvider {
|
||||
|
||||
List<String> getCompletionCandidates(IJavaProject project);
|
||||
|
||||
}
|
||||
@@ -11,248 +11,235 @@
|
||||
package org.springframework.ide.vscode.boot.java.beans;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
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.ArrayInitializer;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
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.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class DependsOnCompletionProcessor implements CompletionProvider {
|
||||
public class DependsOnCompletionProcessor implements AnnotationAttributeCompletionProvider {
|
||||
|
||||
private final JavaProjectFinder projectFinder;
|
||||
private final SpringMetamodelIndex springIndex;
|
||||
|
||||
public DependsOnCompletionProcessor(JavaProjectFinder projectFinder, SpringMetamodelIndex springIndex) {
|
||||
this.projectFinder = projectFinder;
|
||||
public DependsOnCompletionProcessor(SpringMetamodelIndex springIndex) {
|
||||
this.springIndex = springIndex;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type, int offset, TextDocument doc, Collection<ICompletionProposal> completions) {
|
||||
//
|
||||
// Optional<IJavaProject> optionalProject = projectFinder.find(doc.getId());
|
||||
// if (!optionalProject.isPresent()) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// IJavaProject project = optionalProject.get();
|
||||
//
|
||||
// try {
|
||||
//
|
||||
// // case: @DependsOn(<*>)
|
||||
// if (node == annotation && doc.get(offset - 1, 2).endsWith("()")) {
|
||||
// Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
|
||||
//
|
||||
// for (Bean bean : beans) {
|
||||
//
|
||||
// DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
// edits.replace(offset, offset, "\"" + bean.getName() + "\"");
|
||||
//
|
||||
// DependsOnCompletionProposal proposal = new DependsOnCompletionProposal(edits, bean.getName(), bean.getName(), null);
|
||||
//
|
||||
// completions.add(proposal);
|
||||
// }
|
||||
// }
|
||||
// // case: @DependsOn(prefix<*>)
|
||||
// else if (node instanceof SimpleName && node.getParent() instanceof Annotation) {
|
||||
// computeProposalsForSimpleName(project, node, completions, offset, doc);
|
||||
// }
|
||||
// // case: @DependsOn(value=<*>)
|
||||
// else if (node instanceof SimpleName && node.getParent() instanceof MemberValuePair
|
||||
// && "value".equals(((MemberValuePair)node.getParent()).getName().toString())) {
|
||||
// computeProposalsForSimpleName(project, node, completions, offset, doc);
|
||||
// }
|
||||
// // case: @DependsOn("prefix<*>")
|
||||
// else if (node instanceof StringLiteral && node.getParent() instanceof Annotation) {
|
||||
// if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
// computeProposalsForStringLiteral(project, node, completions, offset, doc);
|
||||
// }
|
||||
// }
|
||||
// else if (node instanceof StringLiteral && node.getParent() instanceof ArrayInitializer) {
|
||||
// if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
// computeProposalsForInsideArrayInitializer(project, node, completions, offset, doc);
|
||||
// }
|
||||
// }
|
||||
// // case: @DependsOn(value="prefix<*>")
|
||||
// else if (node instanceof StringLiteral && node.getParent() instanceof MemberValuePair
|
||||
// && "value".equals(((MemberValuePair)node.getParent()).getName().toString())) {
|
||||
// if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
// computeProposalsForStringLiteral(project, node, completions, offset, doc);
|
||||
// }
|
||||
// }
|
||||
// // case: @DependsOn({<*>})
|
||||
// else if (node instanceof ArrayInitializer && node.getParent() instanceof Annotation) {
|
||||
// computeProposalsForArrayInitializr(project, (ArrayInitializer) node, completions, offset, doc);
|
||||
// }
|
||||
// }
|
||||
// catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void computeProposalsForSimpleName(IJavaProject project, ASTNode node, Collection<ICompletionProposal> completions, int offset, IDocument doc) {
|
||||
// String prefix = identifyPropertyPrefix(node.toString(), offset - node.getStartPosition());
|
||||
//
|
||||
// int startOffset = node.getStartPosition();
|
||||
// int endOffset = node.getStartPosition() + node.getLength();
|
||||
//
|
||||
// String proposalPrefix = "\"";
|
||||
// String proposalPostfix = "\"";
|
||||
//
|
||||
// Set<String> mentionedBeans = alreadyMentionedBeans(node);
|
||||
//
|
||||
// Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
|
||||
// List<Bean> matchingBeans = Arrays.stream(beans)
|
||||
// .filter(bean -> bean.getName().toLowerCase().startsWith(prefix.toLowerCase()))
|
||||
// .filter(bean -> !mentionedBeans.contains(bean.getName()))
|
||||
// .collect(Collectors.toList());
|
||||
//
|
||||
// for (Bean bean : matchingBeans) {
|
||||
//
|
||||
// DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
// edits.replace(startOffset, endOffset, proposalPrefix + bean.getName() + proposalPostfix);
|
||||
//
|
||||
// DependsOnCompletionProposal proposal = new DependsOnCompletionProposal(edits, bean.getName(), bean.getName(), null);
|
||||
//
|
||||
// completions.add(proposal);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void computeProposalsForStringLiteral(IJavaProject project, ASTNode node, Collection<ICompletionProposal> completions, int offset, IDocument doc) throws BadLocationException {
|
||||
// int length = offset - (node.getStartPosition() + 1);
|
||||
//
|
||||
// String prefix = identifyPropertyPrefix(doc.get(node.getStartPosition() + 1, length), length);
|
||||
// int startOffset = offset - prefix.length();
|
||||
// int endOffset = offset;
|
||||
//
|
||||
// Set<String> mentionedBeans = alreadyMentionedBeans(node);
|
||||
//
|
||||
// Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
|
||||
//
|
||||
// final String filterPrefix = prefix;
|
||||
// List<Bean> matchingBeans = Arrays.stream(beans)
|
||||
// .filter(bean -> bean.getName().toLowerCase().startsWith(filterPrefix.toLowerCase()))
|
||||
// .filter(bean -> !mentionedBeans.contains(bean.getName()))
|
||||
// .collect(Collectors.toList());
|
||||
//
|
||||
// for (Bean bean : matchingBeans) {
|
||||
//
|
||||
// DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
// edits.replace(startOffset, endOffset, bean.getName());
|
||||
//
|
||||
// DependsOnCompletionProposal proposal = new DependsOnCompletionProposal(edits, bean.getName(), bean.getName(), null);
|
||||
//
|
||||
// completions.add(proposal);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void computeProposalsForArrayInitializr(IJavaProject project, ArrayInitializer node, Collection<ICompletionProposal> completions, int offset, IDocument doc) {
|
||||
// Set<String> mentionedBeans = alreadyMentionedBeans(node);
|
||||
//
|
||||
// Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
|
||||
// List<Bean> filteredBeans = Arrays.stream(beans)
|
||||
// .filter(bean -> !mentionedBeans.contains(bean.getName()))
|
||||
// .collect(Collectors.toList());
|
||||
//
|
||||
// for (Bean bean : filteredBeans) {
|
||||
//
|
||||
// DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
// edits.replace(offset, offset, "\"" + bean.getName() + "\"");
|
||||
//
|
||||
// DependsOnCompletionProposal proposal = new DependsOnCompletionProposal(edits, bean.getName(), bean.getName(), null);
|
||||
//
|
||||
// completions.add(proposal);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void computeProposalsForInsideArrayInitializer(IJavaProject project, ASTNode node, Collection<ICompletionProposal> completions, int offset, TextDocument doc) throws BadLocationException {
|
||||
// int length = offset - (node.getStartPosition() + 1);
|
||||
// if (length >= 0) {
|
||||
// computeProposalsForStringLiteral(project, node, completions, offset, doc);
|
||||
// }
|
||||
// else {
|
||||
// Set<String> mentionedBeans = alreadyMentionedBeans(node);
|
||||
//
|
||||
// Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
|
||||
// List<Bean> filteredBeans = Arrays.stream(beans)
|
||||
// .filter(bean -> !mentionedBeans.contains(bean.getName()))
|
||||
// .collect(Collectors.toList());
|
||||
//
|
||||
// for (Bean bean : filteredBeans) {
|
||||
//
|
||||
// DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
// edits.replace(offset, offset, "\"" + bean.getName() + "\",");
|
||||
//
|
||||
// DependsOnCompletionProposal proposal = new DependsOnCompletionProposal(edits, bean.getName(), bean.getName(), null);
|
||||
//
|
||||
// completions.add(proposal);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private String identifyPropertyPrefix(String nodeContent, int offset) {
|
||||
// String result = nodeContent.substring(0, offset);
|
||||
//
|
||||
// int i = offset - 1;
|
||||
// while (i >= 0) {
|
||||
// char c = nodeContent.charAt(i);
|
||||
// if (c == '}' || c == '{' || c == '$' || c == '#') {
|
||||
// result = result.substring(i + 1, offset);
|
||||
// break;
|
||||
// }
|
||||
// i--;
|
||||
// }
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// private Set<String> alreadyMentionedBeans(ASTNode node) {
|
||||
// Set<String> result = new HashSet<>();
|
||||
//
|
||||
// ArrayInitializer arrayNode = null;
|
||||
// while (node != null && arrayNode == null && !(node instanceof Annotation)) {
|
||||
// if (node instanceof ArrayInitializer) {
|
||||
// arrayNode = (ArrayInitializer) node;
|
||||
// }
|
||||
// else {
|
||||
// node = node.getParent();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (arrayNode != null) {
|
||||
// List<?> expressions = arrayNode.expressions();
|
||||
// for (Object expression : expressions) {
|
||||
// if (expression instanceof StringLiteral) {
|
||||
// StringLiteral stringExr = (StringLiteral) expression;
|
||||
// String value = stringExr.getLiteralValue();
|
||||
// result.add(value);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type, int offset, TextDocument doc, Collection<ICompletionProposal> completions) {
|
||||
|
||||
Optional<IJavaProject> optionalProject = projectFinder.find(doc.getId());
|
||||
if (!optionalProject.isPresent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
IJavaProject project = optionalProject.get();
|
||||
|
||||
try {
|
||||
|
||||
// case: @DependsOn(<*>)
|
||||
if (node == annotation && doc.get(offset - 1, 2).endsWith("()")) {
|
||||
Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
|
||||
|
||||
for (Bean bean : beans) {
|
||||
|
||||
DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
edits.replace(offset, offset, "\"" + bean.getName() + "\"");
|
||||
|
||||
DependsOnCompletionProposal proposal = new DependsOnCompletionProposal(edits, bean.getName(), bean.getName(), null);
|
||||
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
// case: @DependsOn(prefix<*>)
|
||||
else if (node instanceof SimpleName && node.getParent() instanceof Annotation) {
|
||||
computeProposalsForSimpleName(project, node, completions, offset, doc);
|
||||
}
|
||||
// case: @DependsOn(value=<*>)
|
||||
else if (node instanceof SimpleName && node.getParent() instanceof MemberValuePair
|
||||
&& "value".equals(((MemberValuePair)node.getParent()).getName().toString())) {
|
||||
computeProposalsForSimpleName(project, node, completions, offset, doc);
|
||||
}
|
||||
// case: @DependsOn("prefix<*>")
|
||||
else if (node instanceof StringLiteral && node.getParent() instanceof Annotation) {
|
||||
if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
computeProposalsForStringLiteral(project, node, completions, offset, doc);
|
||||
}
|
||||
}
|
||||
else if (node instanceof StringLiteral && node.getParent() instanceof ArrayInitializer) {
|
||||
if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
computeProposalsForInsideArrayInitializer(project, node, completions, offset, doc);
|
||||
}
|
||||
}
|
||||
// case: @DependsOn(value="prefix<*>")
|
||||
else if (node instanceof StringLiteral && node.getParent() instanceof MemberValuePair
|
||||
&& "value".equals(((MemberValuePair)node.getParent()).getName().toString())) {
|
||||
if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
computeProposalsForStringLiteral(project, node, completions, offset, doc);
|
||||
}
|
||||
}
|
||||
// case: @DependsOn({<*>})
|
||||
else if (node instanceof ArrayInitializer && node.getParent() instanceof Annotation) {
|
||||
computeProposalsForArrayInitializr(project, (ArrayInitializer) node, completions, offset, doc);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void computeProposalsForSimpleName(IJavaProject project, ASTNode node, Collection<ICompletionProposal> completions, int offset, IDocument doc) {
|
||||
String prefix = identifyPropertyPrefix(node.toString(), offset - node.getStartPosition());
|
||||
|
||||
int startOffset = node.getStartPosition();
|
||||
int endOffset = node.getStartPosition() + node.getLength();
|
||||
|
||||
String proposalPrefix = "\"";
|
||||
String proposalPostfix = "\"";
|
||||
|
||||
Set<String> mentionedBeans = alreadyMentionedBeans(node);
|
||||
|
||||
Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
|
||||
List<Bean> matchingBeans = Arrays.stream(beans)
|
||||
.filter(bean -> bean.getName().toLowerCase().startsWith(prefix.toLowerCase()))
|
||||
.filter(bean -> !mentionedBeans.contains(bean.getName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (Bean bean : matchingBeans) {
|
||||
|
||||
DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
edits.replace(startOffset, endOffset, proposalPrefix + bean.getName() + proposalPostfix);
|
||||
|
||||
DependsOnCompletionProposal proposal = new DependsOnCompletionProposal(edits, bean.getName(), bean.getName(), null);
|
||||
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
|
||||
private void computeProposalsForStringLiteral(IJavaProject project, ASTNode node, Collection<ICompletionProposal> completions, int offset, IDocument doc) throws BadLocationException {
|
||||
int length = offset - (node.getStartPosition() + 1);
|
||||
|
||||
String prefix = identifyPropertyPrefix(doc.get(node.getStartPosition() + 1, length), length);
|
||||
int startOffset = offset - prefix.length();
|
||||
int endOffset = offset;
|
||||
|
||||
Set<String> mentionedBeans = alreadyMentionedBeans(node);
|
||||
|
||||
Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
|
||||
|
||||
final String filterPrefix = prefix;
|
||||
List<Bean> matchingBeans = Arrays.stream(beans)
|
||||
.filter(bean -> bean.getName().toLowerCase().startsWith(filterPrefix.toLowerCase()))
|
||||
.filter(bean -> !mentionedBeans.contains(bean.getName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (Bean bean : matchingBeans) {
|
||||
|
||||
DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
edits.replace(startOffset, endOffset, bean.getName());
|
||||
|
||||
DependsOnCompletionProposal proposal = new DependsOnCompletionProposal(edits, bean.getName(), bean.getName(), null);
|
||||
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
|
||||
private void computeProposalsForArrayInitializr(IJavaProject project, ArrayInitializer node, Collection<ICompletionProposal> completions, int offset, IDocument doc) {
|
||||
Set<String> mentionedBeans = alreadyMentionedBeans(node);
|
||||
|
||||
Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
|
||||
List<Bean> filteredBeans = Arrays.stream(beans)
|
||||
.filter(bean -> !mentionedBeans.contains(bean.getName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (Bean bean : filteredBeans) {
|
||||
|
||||
DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
edits.replace(offset, offset, "\"" + bean.getName() + "\"");
|
||||
|
||||
DependsOnCompletionProposal proposal = new DependsOnCompletionProposal(edits, bean.getName(), bean.getName(), null);
|
||||
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
|
||||
private void computeProposalsForInsideArrayInitializer(IJavaProject project, ASTNode node, Collection<ICompletionProposal> completions, int offset, TextDocument doc) throws BadLocationException {
|
||||
int length = offset - (node.getStartPosition() + 1);
|
||||
if (length >= 0) {
|
||||
computeProposalsForStringLiteral(project, node, completions, offset, doc);
|
||||
}
|
||||
else {
|
||||
Set<String> mentionedBeans = alreadyMentionedBeans(node);
|
||||
|
||||
Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
|
||||
List<Bean> filteredBeans = Arrays.stream(beans)
|
||||
.filter(bean -> !mentionedBeans.contains(bean.getName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (Bean bean : filteredBeans) {
|
||||
|
||||
DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
edits.replace(offset, offset, "\"" + bean.getName() + "\",");
|
||||
|
||||
DependsOnCompletionProposal proposal = new DependsOnCompletionProposal(edits, bean.getName(), bean.getName(), null);
|
||||
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String identifyPropertyPrefix(String nodeContent, int offset) {
|
||||
String result = nodeContent.substring(0, offset);
|
||||
|
||||
int i = offset - 1;
|
||||
while (i >= 0) {
|
||||
char c = nodeContent.charAt(i);
|
||||
if (c == '}' || c == '{' || c == '$' || c == '#') {
|
||||
result = result.substring(i + 1, offset);
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Set<String> alreadyMentionedBeans(ASTNode node) {
|
||||
Set<String> result = new HashSet<>();
|
||||
|
||||
ArrayInitializer arrayNode = null;
|
||||
while (node != null && arrayNode == null && !(node instanceof Annotation)) {
|
||||
if (node instanceof ArrayInitializer) {
|
||||
arrayNode = (ArrayInitializer) node;
|
||||
}
|
||||
else {
|
||||
node = node.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
if (arrayNode != null) {
|
||||
List<?> expressions = arrayNode.expressions();
|
||||
for (Object expression : expressions) {
|
||||
if (expression instanceof StringLiteral) {
|
||||
StringLiteral stringExr = (StringLiteral) expression;
|
||||
String value = stringExr.getLiteralValue();
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
public List<String> getCompletionCandidates(IJavaProject project) {
|
||||
return Arrays.stream(this.springIndex.getBeansOfProject(project.getElementName()))
|
||||
.map(bean -> bean.getName())
|
||||
.distinct()
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom
|
||||
* 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.beans;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class QualifierCompletionProvider implements AnnotationAttributeCompletionProvider {
|
||||
|
||||
private final SpringMetamodelIndex springIndex;
|
||||
|
||||
public QualifierCompletionProvider(SpringMetamodelIndex springIndex) {
|
||||
this.springIndex = springIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getCompletionCandidates(IJavaProject project) {
|
||||
|
||||
Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
|
||||
|
||||
return Stream.concat(
|
||||
findAllQualifiers(beans),
|
||||
Arrays.stream(beans).map(bean -> bean.getName()))
|
||||
.distinct()
|
||||
.toList();
|
||||
}
|
||||
|
||||
private Stream<String> findAllQualifiers(Bean[] beans) {
|
||||
|
||||
Stream<String> qualifiersFromBeans = Arrays.stream(beans)
|
||||
// annotations from beans themselves
|
||||
.flatMap(bean -> Arrays.stream(bean.getAnnotations()))
|
||||
.filter(annotation -> Annotations.QUALIFIER.equals(annotation.getAnnotationType()))
|
||||
.filter(annotation -> annotation.getAttributes() != null && annotation.getAttributes().containsKey("value") && annotation.getAttributes().get("value").length == 1)
|
||||
.map(annotation -> annotation.getAttributes().get("value")[0]);
|
||||
|
||||
Stream<String> qualifiersFromInjectionPoints = Arrays.stream(beans)
|
||||
// annotations from beans themselves
|
||||
.filter(bean -> bean.getInjectionPoints() != null)
|
||||
.flatMap(bean -> Arrays.stream(bean.getInjectionPoints()))
|
||||
.filter(injectionPoint -> injectionPoint.getAnnotations() != null)
|
||||
.flatMap(injectionPoint -> Arrays.stream(injectionPoint.getAnnotations()))
|
||||
.filter(annotation -> Annotations.QUALIFIER.equals(annotation.getAnnotationType()))
|
||||
.filter(annotation -> annotation.getAttributes() != null && annotation.getAttributes().containsKey("value") && annotation.getAttributes().get("value").length == 1)
|
||||
.map(annotation -> annotation.getAttributes().get("value")[0]);
|
||||
|
||||
return Stream.concat(qualifiersFromBeans, qualifiersFromInjectionPoints);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 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
|
||||
@@ -10,76 +10,84 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.scope;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class ScopeCompletionProcessor implements CompletionProvider {
|
||||
public class ScopeCompletionProcessor implements AnnotationAttributeCompletionProvider {
|
||||
|
||||
private static final List<String> SCOPE_COMPLETIONS = List.of(
|
||||
"application",
|
||||
"globalSession",
|
||||
"prototype",
|
||||
"request",
|
||||
"session",
|
||||
"singleton",
|
||||
"websocket"
|
||||
);
|
||||
|
||||
@Override
|
||||
public void provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type,
|
||||
int offset, TextDocument doc, Collection<ICompletionProposal> completions) {
|
||||
|
||||
try {
|
||||
if (node instanceof SimpleName && node.getParent() instanceof MemberValuePair) {
|
||||
MemberValuePair memberPair = (MemberValuePair) node.getParent();
|
||||
|
||||
// case: @Scope(value=<*>)
|
||||
if ("value".equals(memberPair.getName().toString()) && memberPair.getValue().toString().equals("$missing$")) {
|
||||
for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
|
||||
ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, offset, offset, "");
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
}
|
||||
// case: @Scope(<*>)
|
||||
else if (node == annotation && doc.get(offset - 1, 2).endsWith("()")) {
|
||||
for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
|
||||
ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, offset, offset, "");
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
else if (node instanceof StringLiteral && node.getParent() instanceof Annotation) {
|
||||
// case: @Scope("...")
|
||||
if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
String prefix = doc.get(node.getStartPosition(), offset - node.getStartPosition());
|
||||
for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
|
||||
if (completion.getValue().startsWith(prefix)) {
|
||||
ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, node.getStartPosition(), node.getStartPosition() + node.getLength(), prefix);
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (node instanceof StringLiteral && node.getParent() instanceof MemberValuePair) {
|
||||
MemberValuePair memberPair = (MemberValuePair) node.getParent();
|
||||
|
||||
// case: @Scope(value=<*>)
|
||||
if ("value".equals(memberPair.getName().toString()) && node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
String prefix = doc.get(node.getStartPosition(), offset - node.getStartPosition());
|
||||
for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
|
||||
if (completion.getValue().startsWith(prefix)) {
|
||||
ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, node.getStartPosition(), node.getStartPosition() + node.getLength(), prefix);
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public List<String> getCompletionCandidates(IJavaProject project) {
|
||||
return SCOPE_COMPLETIONS;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type,
|
||||
// int offset, TextDocument doc, Collection<ICompletionProposal> completions) {
|
||||
//
|
||||
// try {
|
||||
// if (node instanceof SimpleName && node.getParent() instanceof MemberValuePair) {
|
||||
// MemberValuePair memberPair = (MemberValuePair) node.getParent();
|
||||
//
|
||||
// // case: @Scope(value=<*>)
|
||||
// if ("value".equals(memberPair.getName().toString()) && memberPair.getValue().toString().equals("$missing$")) {
|
||||
// for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
|
||||
// ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, offset, offset, "");
|
||||
// completions.add(proposal);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // case: @Scope(<*>)
|
||||
// else if (node == annotation && doc.get(offset - 1, 2).endsWith("()")) {
|
||||
// for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
|
||||
// ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, offset, offset, "");
|
||||
// completions.add(proposal);
|
||||
// }
|
||||
// }
|
||||
// else if (node instanceof StringLiteral && node.getParent() instanceof Annotation) {
|
||||
// // case: @Scope("...")
|
||||
// if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
// String prefix = doc.get(node.getStartPosition(), offset - node.getStartPosition());
|
||||
// for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
|
||||
// if (completion.getValue().startsWith(prefix)) {
|
||||
// ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, node.getStartPosition(), node.getStartPosition() + node.getLength(), prefix);
|
||||
// completions.add(proposal);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else if (node instanceof StringLiteral && node.getParent() instanceof MemberValuePair) {
|
||||
// MemberValuePair memberPair = (MemberValuePair) node.getParent();
|
||||
//
|
||||
// // case: @Scope(value=<*>)
|
||||
// if ("value".equals(memberPair.getName().toString()) && node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
// String prefix = doc.get(node.getStartPosition(), offset - node.getStartPosition());
|
||||
// for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
|
||||
// if (completion.getValue().startsWith(prefix)) {
|
||||
// ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, node.getStartPosition(), node.getStartPosition() + node.getLength(), prefix);
|
||||
// completions.add(proposal);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -46,9 +46,9 @@ public class PropertyIndexHarness {
|
||||
@Override
|
||||
public SpringPropertyIndex getIndex(IDocument doc) {
|
||||
synchronized (PropertyIndexHarness.this) {
|
||||
if (index==null) {
|
||||
if (index == null) {
|
||||
IClasspath classpath = testProject == null ? null : testProject.getClasspath();
|
||||
index = SpringPropertyIndex.builder(valueProviders).withClasspath(classpath).build();
|
||||
index = SpringPropertyIndex.builder(valueProviders).withClasspath(classpath).build();
|
||||
for (ConfigurationMetadataProperty propertyInfo : datas.values()) {
|
||||
index.add(propertyInfo);
|
||||
}
|
||||
|
||||
@@ -92,6 +92,12 @@ public class DependsOnCompletionProviderTest {
|
||||
assertCompletions("@DependsOn(<*>)", 2, "@DependsOn(\"bean1\"<*>)");
|
||||
}
|
||||
|
||||
// TODO: not yet working, needs more groundwork due to the parser skipping these non-valid parts of the AST
|
||||
// @Test
|
||||
// public void testDependsOnCompletionWithoutQuotesWithoutPrefixWithoutClosingBracket() throws Exception {
|
||||
// assertCompletions("@DependsOn(<*>", 2, "@DependsOn(\"bean1\")<*>");
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void testDependsOnCompletionWithoutQuotesWithPrefix() throws Exception {
|
||||
assertCompletions("@DependsOn(be<*>)", 2, "@DependsOn(\"bean1\"<*>)");
|
||||
@@ -102,11 +108,23 @@ public class DependsOnCompletionProviderTest {
|
||||
assertCompletions("@DependsOn(value=<*>)", 2, "@DependsOn(value=\"bean1\"<*>)");
|
||||
}
|
||||
|
||||
// TODO: not yet working, needs more groundwork due to the parser skipping these non-valid parts of the AST
|
||||
// @Test
|
||||
// public void testDependsOnCompletionWithoutQuotesWithAttributeNameAndDefaultSpaces() throws Exception {
|
||||
// assertCompletions("@DependsOn(value = <*>)", 2, "@DependsOn(value = \"bean1\"<*>)");
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void testDependsOnCompletionInsideOfQuotesWithoutPrefix() throws Exception {
|
||||
assertCompletions("@DependsOn(\"<*>\")", 2, "@DependsOn(\"bean1<*>\")");
|
||||
}
|
||||
|
||||
// TODO: not yet working, needs more groundwork due to the parser skipping these non-valid parts of the AST
|
||||
// @Test
|
||||
// public void testDependsOnCompletionOpeningQuoteOnlyWithoutPrefix() throws Exception {
|
||||
// assertCompletions("@DependsOn(\"<*>)", 2, "@DependsOn(\"bean1<*>\")");
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void testDependsOnCompletionWithoutQuotesWithoutPrefixInsideArray() throws Exception {
|
||||
assertCompletions("@DependsOn({<*>})", 2, "@DependsOn({\"bean1\"<*>})");
|
||||
@@ -144,7 +162,7 @@ public class DependsOnCompletionProviderTest {
|
||||
|
||||
@Test
|
||||
public void testDependsOnCompletionInsideOfQuotesWithPrefixAndReplacedPostfix() throws Exception {
|
||||
assertCompletions("@DependsOn(\"be<*>xxx\")", 2, "@DependsOn(\"bean1<*>xxx\")");
|
||||
assertCompletions("@DependsOn(\"be<*>xxx\")", 2, "@DependsOn(\"bean1<*>\")");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -140,7 +140,7 @@ public class QualifierCompletionProviderTest {
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionInsideOfQuotesWithPrefixAndReplacedPostfix() throws Exception {
|
||||
assertCompletions("@Qualifier(\"be<*>xxx\")", 2, "@Qualifier(\"bean1<*>xxx\")");
|
||||
assertCompletions("@Qualifier(\"be<*>xxx\")", 2, "@Qualifier(\"bean1<*>\")");
|
||||
}
|
||||
|
||||
private void assertCompletions(String completionLine, int noOfExpectedCompletions, String expectedCompletedLine) throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 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
|
||||
@@ -10,12 +10,13 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.scope.test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import org.eclipse.lsp4j.CompletionItem;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -50,10 +51,6 @@ public class ScopeCompletionTest {
|
||||
harness.intialize(null);
|
||||
}
|
||||
|
||||
// private IJavaProject getTestProject() {
|
||||
// return testProject;
|
||||
// }
|
||||
|
||||
@Test
|
||||
void testEmptyBracketsCompletion() throws Exception {
|
||||
prepareCase("@Scope(\"onClass\")", "@Scope(<*>)");
|
||||
@@ -71,13 +68,13 @@ public class ScopeCompletionTest {
|
||||
void testEmptyStringLiteralCompletion() throws Exception {
|
||||
prepareCase("@Scope(\"onClass\")", "@Scope(\"<*>\")");
|
||||
assertAnnotationCompletions(
|
||||
"@Scope(\"application\"<*>)",
|
||||
"@Scope(\"globalSession\"<*>)",
|
||||
"@Scope(\"prototype\"<*>)",
|
||||
"@Scope(\"request\"<*>)",
|
||||
"@Scope(\"session\"<*>)",
|
||||
"@Scope(\"singleton\"<*>)",
|
||||
"@Scope(\"websocket\"<*>)");
|
||||
"@Scope(\"application<*>\")",
|
||||
"@Scope(\"globalSession<*>\")",
|
||||
"@Scope(\"prototype<*>\")",
|
||||
"@Scope(\"request<*>\")",
|
||||
"@Scope(\"session<*>\")",
|
||||
"@Scope(\"singleton<*>\")",
|
||||
"@Scope(\"websocket<*>\")");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -97,20 +94,20 @@ public class ScopeCompletionTest {
|
||||
void testEmptyValueStringLiteralCompletion() throws Exception {
|
||||
prepareCase("@Scope(\"onClass\")", "@Scope(value=\"<*>\")");
|
||||
assertAnnotationCompletions(
|
||||
"@Scope(value=\"application\"<*>)",
|
||||
"@Scope(value=\"globalSession\"<*>)",
|
||||
"@Scope(value=\"prototype\"<*>)",
|
||||
"@Scope(value=\"request\"<*>)",
|
||||
"@Scope(value=\"session\"<*>)",
|
||||
"@Scope(value=\"singleton\"<*>)",
|
||||
"@Scope(value=\"websocket\"<*>)");
|
||||
"@Scope(value=\"application<*>\")",
|
||||
"@Scope(value=\"globalSession<*>\")",
|
||||
"@Scope(value=\"prototype<*>\")",
|
||||
"@Scope(value=\"request<*>\")",
|
||||
"@Scope(value=\"session<*>\")",
|
||||
"@Scope(value=\"singleton<*>\")",
|
||||
"@Scope(value=\"websocket<*>\")");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPrefixWithClosingQuotesCompletion() throws Exception {
|
||||
prepareCase("@Scope(\"onClass\")", "@Scope(\"pro<*>\")");
|
||||
assertAnnotationCompletions(
|
||||
"@Scope(\"prototype\"<*>)");
|
||||
"@Scope(\"prototype<*>\")");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -123,7 +120,7 @@ public class ScopeCompletionTest {
|
||||
void testValuePrefixWithClosingQuotesCompletion() throws Exception {
|
||||
prepareCase("@Scope(\"onClass\")", "@Scope(value=\"pro<*>\")");
|
||||
assertAnnotationCompletions(
|
||||
"@Scope(value=\"prototype\"<*>)");
|
||||
"@Scope(value=\"prototype<*>\")");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -136,7 +133,7 @@ public class ScopeCompletionTest {
|
||||
void testPrefixReplaceRestCompletion() throws Exception {
|
||||
prepareCase("@Scope(\"onClass\")", "@Scope(\"pro<*>something\")");
|
||||
assertAnnotationCompletions(
|
||||
"@Scope(\"prototype\"<*>)");
|
||||
"@Scope(\"prototype<*>\")");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -147,7 +144,7 @@ public class ScopeCompletionTest {
|
||||
|
||||
private void prepareCase(String selectedAnnotation, String annotationStatementBeforeTest) throws Exception {
|
||||
InputStream resource = this.getClass().getResourceAsStream("/test-projects/test-annotations/src/main/java/org/test/TestScopeCompletion.java");
|
||||
String content = IOUtils.toString(resource);
|
||||
String content = IOUtils.toString(resource, Charset.defaultCharset());
|
||||
|
||||
content = content.replace(selectedAnnotation, annotationStatementBeforeTest);
|
||||
editor = new Editor(harness, content, LanguageId.JAVA);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2020 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
|
||||
@@ -14,6 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -63,7 +64,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
public class ValueCompletionTest {
|
||||
|
||||
@Autowired private BootLanguageServerHarness harness;
|
||||
@Autowired private IJavaProject testProject;
|
||||
@Autowired private JavaProjectFinder projectFinder;
|
||||
|
||||
private Editor editor;
|
||||
@@ -132,10 +132,6 @@ public class ValueCompletionTest {
|
||||
harness.intialize(null);
|
||||
}
|
||||
|
||||
private IJavaProject getTestProject() {
|
||||
return testProject;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPrefixIdentification() {
|
||||
ValueCompletionProcessor processor = new ValueCompletionProcessor(projectFinder, null, null);
|
||||
@@ -392,7 +388,7 @@ public class ValueCompletionTest {
|
||||
|
||||
private void prepareCase(String selectedAnnotation, String annotationStatementBeforeTest) throws Exception {
|
||||
InputStream resource = this.getClass().getResourceAsStream("/test-projects/test-annotations/src/main/java/org/test/TestValueCompletion.java");
|
||||
String content = IOUtils.toString(resource);
|
||||
String content = IOUtils.toString(resource, Charset.defaultCharset());
|
||||
|
||||
content = content.replace(selectedAnnotation, annotationStatementBeforeTest);
|
||||
editor = new Editor(harness, content, LanguageId.JAVA);
|
||||
|
||||
Reference in New Issue
Block a user