Scope completions done

This commit is contained in:
BoykoAlex
2022-02-07 19:56:21 -05:00
parent 50a65d890a
commit 162de16a77
23 changed files with 479 additions and 232 deletions

View File

@@ -109,6 +109,11 @@
<artifactId>rewrite-java</artifactId>
<version>${rewrite-version}</version>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-java-11</artifactId>
<version>${rewrite-version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>

View File

@@ -25,7 +25,7 @@ import org.springframework.ide.vscode.boot.java.scope.ScopeCompletionProcessor;
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippet;
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippetContext;
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippetManager;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.boot.java.utils.ORCompilationUnitCache;
import org.springframework.ide.vscode.boot.java.value.ValueCompletionProcessor;
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
@@ -86,7 +86,7 @@ public class BootJavaCompletionEngineConfigurer {
BootLanguageServerParams params,
@Qualifier("adHocProperties") ProjectBasedPropertyIndexProvider adHocProperties,
JavaSnippetManager snippetManager,
CompilationUnitCache cuCache) {
ORCompilationUnitCache cuCache) {
SpringPropertyIndexProvider indexProvider = params.indexProvider;
JavaProjectFinder javaProjectFinder = params.projectFinder;
Map<String, CompletionProvider> providers = new HashMap<>();

View File

@@ -155,10 +155,14 @@ public class BootLanguageServerBootApp {
return SourceLinkFactory.createSourceLinks(server, cuCache, params.projectFinder);
}
@Bean ORCompilationUnitCache cuCache(SimpleLanguageServer server, BootLanguageServerParams params) {
@Bean ORCompilationUnitCache orcuCache(SimpleLanguageServer server, BootLanguageServerParams params) {
return new ORCompilationUnitCache(params.projectFinder, server, params.projectObserver);
}
@Bean CompilationUnitCache cuCache(SimpleLanguageServer server, BootLanguageServerParams params) {
return new CompilationUnitCache(params.projectFinder, server, params.projectObserver);
}
@Bean SpringXMLCompletionEngine xmlCompletionEngine(SimpleLanguageServer server, JavaProjectFinder projectFinder, SpringSymbolIndex symbolIndex, BootJavaConfig config) {
return new SpringXMLCompletionEngine(server, projectFinder, symbolIndex, config);
}
@@ -188,7 +192,7 @@ public class BootLanguageServerBootApp {
}
}
@Bean JavaElementLocationProvider javaElementLocationProvider(SimpleLanguageServer server, CompilationUnitCache cuCache, JavaDocumentUriProvider javaDocUriProvider) {
@Bean JavaElementLocationProvider javaElementLocationProvider(SimpleLanguageServer server, ORCompilationUnitCache cuCache, JavaDocumentUriProvider javaDocUriProvider) {
switch (LspClient.currentClient()) {
case ECLIPSE:
case VSCODE:

View File

@@ -11,7 +11,6 @@
package org.springframework.ide.vscode.boot.app;
import java.util.List;
import java.util.Optional;
import org.eclipse.lsp4j.MessageType;
import org.slf4j.Logger;

View File

@@ -11,15 +11,18 @@
package org.springframework.ide.vscode.boot.java.data;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
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.TypeDeclaration;
import org.eclipse.lsp4j.CompletionItemKind;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.Annotation;
import org.openrewrite.java.tree.J.ClassDeclaration;
import org.openrewrite.java.tree.JavaType.FullyQualified;
import org.openrewrite.java.tree.TypeUtils;
import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider;
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.util.BadLocationException;
@@ -33,14 +36,14 @@ import org.springframework.util.StringUtils;
public class DataRepositoryCompletionProcessor implements CompletionProvider {
@Override
public void provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type,
public void provideCompletions(J node, Annotation annotation,
int offset, IDocument doc, Collection<ICompletionProposal> completions) {
}
@Override
public void provideCompletions(ASTNode node, int offset, IDocument doc, Collection<ICompletionProposal> completions) {
TypeDeclaration type = ASTUtils.findDeclaringType(node);
DataRepositoryDefinition repo = getDataRepositoryDefinition(type);
public void provideCompletions(J node, int offset, IDocument doc, Collection<ICompletionProposal> completions) {
ClassDeclaration declaration = ORAstUtils.findNode(node, ClassDeclaration.class);
DataRepositoryDefinition repo = getDataRepositoryDefinition(declaration, declaration.getType());
if (repo != null) {
DomainType domainType = repo.getDomainType();
if (domainType != null) {
@@ -100,41 +103,27 @@ public class DataRepositoryCompletionProcessor implements CompletionProvider {
return new FindByCompletionProposal(label.toString(), CompletionItemKind.Method, edits, null, null, Optional.of(additionalEdits), filter);
}
private DataRepositoryDefinition getDataRepositoryDefinition(TypeDeclaration type) {
private DataRepositoryDefinition getDataRepositoryDefinition(ClassDeclaration declaration, FullyQualified type) {
if (type != null) {
ITypeBinding resolvedType = type.resolveBinding();
return getDataRepositoryDefinition(type, resolvedType);
}
return null;
}
private DataRepositoryDefinition getDataRepositoryDefinition(TypeDeclaration type, ITypeBinding resolvedType) {
if (resolvedType != null) {
// interface analysis
ITypeBinding[] interfaces = resolvedType.getInterfaces();
for (ITypeBinding resolvedInterface : interfaces) {
String simplifiedType = null;
if (resolvedInterface.isParameterizedType()) {
simplifiedType = resolvedInterface.getBinaryName();
}
else {
simplifiedType = resolvedType.getQualifiedName();
}
List<FullyQualified> interfaces = type.getInterfaces();
for (FullyQualified resolvedInterface : interfaces) {
String simplifiedType = resolvedInterface.getFullyQualifiedName();
if (Constants.REPOSITORY_TYPE.equals(simplifiedType)) {
DomainType domainType = null;
if (resolvedInterface.isParameterizedType()) {
ITypeBinding[] typeParameters = resolvedInterface.getTypeArguments();
if (typeParameters != null && typeParameters.length > 0) {
domainType = new DomainType(typeParameters[0]);
}
}
// TODO Fix for OR AST
// if (resolvedInterface.isParameterizedType()) {
// ITypeBinding[] typeParameters = resolvedInterface.getTypeArguments();
// if (typeParameters != null && typeParameters.length > 0) {
// domainType = new DomainType(typeParameters[0]);
// }
// }
return createDataRepositoryDefinitionFromType(domainType);
}
else {
DataRepositoryDefinition repo = getDataRepositoryDefinition(type, resolvedInterface);
DataRepositoryDefinition repo = getDataRepositoryDefinition(declaration, resolvedInterface);
if (repo != null) {
return repo;
}
@@ -142,9 +131,9 @@ public class DataRepositoryCompletionProcessor implements CompletionProvider {
}
// super type analysis
ITypeBinding superclass = resolvedType.getSuperclass();
FullyQualified superclass = type.getSupertype();
if (superclass != null) {
return getDataRepositoryDefinition(type, superclass);
return getDataRepositoryDefinition(declaration, superclass);
}
}
return null;

View File

@@ -15,12 +15,13 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Map;
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.NodeFinder;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.Annotation;
import org.openrewrite.java.tree.JavaType.FullyQualified;
import org.openrewrite.java.tree.TypeUtils;
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippetManager;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
import org.springframework.ide.vscode.boot.java.utils.ORCompilationUnitCache;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.languageserver.util.LanguageSpecific;
@@ -37,9 +38,9 @@ public class BootJavaCompletionEngine implements ICompletionEngine, LanguageSpec
private Map<String, CompletionProvider> completionProviders;
private JavaSnippetManager snippets;
private CompilationUnitCache cuCache;
private ORCompilationUnitCache cuCache;
public BootJavaCompletionEngine(CompilationUnitCache cuCache, Map<String, CompletionProvider> specificProviders, JavaSnippetManager snippets) {
public BootJavaCompletionEngine(ORCompilationUnitCache cuCache, Map<String, CompletionProvider> specificProviders, JavaSnippetManager snippets) {
this.cuCache = cuCache;
this.completionProviders = specificProviders;
this.snippets = snippets;
@@ -49,7 +50,7 @@ public class BootJavaCompletionEngine implements ICompletionEngine, LanguageSpec
public Collection<ICompletionProposal> getCompletions(TextDocument document, int offset) throws Exception {
return cuCache.withCompilationUnit(document, cu -> {
if (cu != null) {
ASTNode node = NodeFinder.perform(cu, offset, 0);
J node = ORAstUtils.findAstNodeAt(cu, offset);
if (node != null) {
Collection<ICompletionProposal> completions = new ArrayList<ICompletionProposal>();
@@ -64,30 +65,25 @@ public class BootJavaCompletionEngine implements ICompletionEngine, LanguageSpec
});
}
private void collectCompletionsForAnnotations(ASTNode node, int offset, IDocument doc, Collection<ICompletionProposal> completions) {
Annotation annotation = null;
ASTNode exactNode = node;
private void collectCompletionsForAnnotations(J node, int offset, IDocument doc, Collection<ICompletionProposal> completions) {
Annotation annotation = ORAstUtils.findNode(node, Annotation.class);
J exactNode = node;
while (node != null && !(node instanceof Annotation)) {
node = node.getParent();
}
if (node != null) {
annotation = (Annotation) node;
ITypeBinding type = annotation.resolveTypeBinding();
if (annotation != null) {
FullyQualified type = TypeUtils.asFullyQualified(annotation.getType());
if (type != null) {
String qualifiedName = type.getQualifiedName();
String qualifiedName = type.getFullyQualifiedName();
if (qualifiedName != null) {
CompletionProvider provider = this.completionProviders.get(qualifiedName);
if (provider != null) {
provider.provideCompletions(exactNode, annotation, type, offset, doc, completions);
provider.provideCompletions(exactNode, annotation, offset, doc, completions);
}
}
}
}
}
private void collectCompletions(ASTNode node, int offset, TextDocument document, Collection<ICompletionProposal> completions) {
private void collectCompletions(J node, int offset, TextDocument document, Collection<ICompletionProposal> completions) {
if (node != null) {
for (CompletionProvider completionProvider : this.completionProviders.values()) {
completionProvider.provideCompletions(node, offset, document, completions);

View File

@@ -12,9 +12,8 @@ package org.springframework.ide.vscode.boot.java.handlers;
import java.util.Collection;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.Annotation;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.util.text.IDocument;
@@ -23,7 +22,7 @@ import org.springframework.ide.vscode.commons.util.text.IDocument;
*/
public interface CompletionProvider {
void provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type, int offset, IDocument doc, Collection<ICompletionProposal> completions);
void provideCompletions(ASTNode node, int offset, IDocument doc, Collection<ICompletionProposal> completions);
void provideCompletions(J node, Annotation annotation, int offset, IDocument doc, Collection<ICompletionProposal> completions);
void provideCompletions(J node, int offset, IDocument doc, Collection<ICompletionProposal> completions);
}

View File

@@ -16,11 +16,12 @@ import java.net.URISyntaxException;
import java.nio.file.Path;
import java.util.Optional;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicReference;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.J.CompilationUnit;
import org.openrewrite.java.tree.TypeUtils;
import org.openrewrite.marker.Position;
import org.openrewrite.marker.Range;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.java.utils.ORCompilationUnitCache;
@@ -30,7 +31,9 @@ import org.springframework.ide.vscode.commons.java.IJavaModuleData;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.javadoc.TypeUrlProviderFromContainerUrl;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.util.text.Region;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
/**
* Base logic for {@link SourceLinks} independent of any client
@@ -132,11 +135,12 @@ public abstract class AbstractSourceLinks implements SourceLinks {
}).map(sourcePath -> findCU(project, sourcePath).orElse(null));
}
protected Region findTypeRegion(CompilationUnit cu, String fqName) {
protected Tuple2<Integer, Integer> findTypeRegion(CompilationUnit cu, String fqName) {
if (cu == null) {
return null;
}
int[] values = new int[] {0, -1};
AtomicReference<Range> range = new AtomicReference<>();
int lastDotIndex = fqName.lastIndexOf('.');
String packageName = fqName.substring(0, lastDotIndex);
String typeName = fqName.substring(lastDotIndex + 1);
@@ -147,11 +151,9 @@ public abstract class AbstractSourceLinks implements SourceLinks {
public org.openrewrite.java.tree.J.ClassDeclaration visitClassDeclaration(org.openrewrite.java.tree.J.ClassDeclaration classDecl, Object p) {
String fqName = classDecl.getType().getFullyQualifiedName();
visitedType.push(fqName);
if (values[1] < 0) {
if (range.get() == null) {
if (String.join("$", visitedType.toArray(new String[visitedType.size()])).equals(typeName)) {
Position pos = classDecl.getName().getMarkers().findFirst(Position.class).orElseThrow();
values[0] = pos.getStartPosition();
values[1] = pos.getLength();
range.set(classDecl.getName().getMarkers().findFirst(Range.class).orElseThrow());
}
}
if (values[1] < 0) {
@@ -165,7 +167,7 @@ public abstract class AbstractSourceLinks implements SourceLinks {
}.visitNonNull(cu, visitedType);
}
return values[1] < 0 ? null : new Region(values[0], values[1]);
return Optional.of(range.get()).map(r -> r.getStart()).map(start -> Tuples.of(start.getLine(), start.getColumn())).orElse(null);
}
}

View File

@@ -27,6 +27,8 @@ import org.springframework.ide.vscode.commons.util.text.Region;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import reactor.util.function.Tuple2;
/**
* Source links for Atom client
*
@@ -54,10 +56,10 @@ public class AtomSourceLinks extends AbstractSourceLinks {
@Override
protected String positionLink(CompilationUnit cu, String fqName) {
if (cu != null) {
Region region = findTypeRegion(cu, fqName);
Tuple2<Integer, Integer> region = findTypeRegion(cu, fqName);
if (region != null) {
int column = cu.getColumnNumber(region.getOffset());
int line = cu.getLineNumber(region.getOffset());
int column = region.getT2();
int line = region.getT1();
StringBuilder sb = new StringBuilder();
sb.append("&line=");
sb.append(line);

View File

@@ -26,21 +26,22 @@ import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.boot.java.utils.ORCompilationUnitCache;
import org.springframework.ide.vscode.commons.java.IField;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.IMember;
import org.springframework.ide.vscode.commons.java.IMethod;
import org.springframework.ide.vscode.commons.java.IType;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
public class DefaultJavaElementLocationProvider implements JavaElementLocationProvider {
private static final Logger log = LoggerFactory.getLogger(DefaultJavaElementLocationProvider.class);
private CompilationUnitCache cuCache;
private ORCompilationUnitCache cuCache;
private JavaDocumentUriProvider javaDocUriProvider;
public DefaultJavaElementLocationProvider(CompilationUnitCache cuCache, JavaDocumentUriProvider javaDocUriProvider) {
public DefaultJavaElementLocationProvider(ORCompilationUnitCache cuCache, JavaDocumentUriProvider javaDocUriProvider) {
this.cuCache = cuCache;
this.javaDocUriProvider = javaDocUriProvider;
}
@@ -63,67 +64,68 @@ public class DefaultJavaElementLocationProvider implements JavaElementLocationPr
if (cu == null) {
return new Range(new Position(0, 0), new Position(0, 0));
}
cu.accept(new ASTVisitor() {
private Range nameRange(SimpleName nameNode) {
int startOffset = nameNode.getStartPosition();
int endOffset = nameNode.getLength() + startOffset;
// Line -1 because for CU lines are starting from 1
return new Range(
new Position(cu.getLineNumber(startOffset) - 1, cu.getColumnNumber(startOffset)),
new Position(cu.getLineNumber(endOffset) - 1, cu.getColumnNumber(endOffset)));
}
@Override
public boolean visit(MethodDeclaration node) {
if (member instanceof IMethod) {
String bindingKey = node.resolveBinding().getKey();
if (matchMethodBindingKeys(memberBindingKey, bindingKey)) {
range.set(nameRange(node.getName()));
return false;
}
}
return true;
}
@Override
public boolean visit(EnumConstantDeclaration node) {
if (member instanceof IField) {
String bindingKey = node.resolveVariable().getKey();
if (memberBindingKey.equals(bindingKey)) {
range.set(nameRange(node.getName()));
return false;
}
}
return true;
}
@Override
public boolean visit(EnumDeclaration node) {
if (member instanceof IType) {
String bindingKey = node.resolveBinding().getKey();
if (memberBindingKey.equals(bindingKey)) {
range.set(nameRange(node.getName()));
return false;
}
}
return true;
}
@Override
public boolean visit(TypeDeclaration node) {
if (member instanceof IType) {
String bindingKey = node.resolveBinding().getKey();
if (memberBindingKey.equals(bindingKey)) {
range.set(nameRange(node.getName()));
return false;
}
}
return true;
}
});
// TODO: Fix for OR AST
// cu.accept(new ASTVisitor() {
//
// private Range nameRange(SimpleName nameNode) {
// int startOffset = nameNode.getStartPosition();
// int endOffset = nameNode.getLength() + startOffset;
//
// // Line -1 because for CU lines are starting from 1
// return new Range(
// new Position(cu.getLineNumber(startOffset) - 1, cu.getColumnNumber(startOffset)),
// new Position(cu.getLineNumber(endOffset) - 1, cu.getColumnNumber(endOffset)));
// }
//
// @Override
// public boolean visit(MethodDeclaration node) {
// if (member instanceof IMethod) {
// String bindingKey = node.resolveBinding().getKey();
// if (matchMethodBindingKeys(memberBindingKey, bindingKey)) {
// range.set(nameRange(node.getName()));
// return false;
// }
// }
// return true;
// }
//
// @Override
// public boolean visit(EnumConstantDeclaration node) {
// if (member instanceof IField) {
// String bindingKey = node.resolveVariable().getKey();
// if (memberBindingKey.equals(bindingKey)) {
// range.set(nameRange(node.getName()));
// return false;
// }
// }
// return true;
// }
//
// @Override
// public boolean visit(EnumDeclaration node) {
// if (member instanceof IType) {
// String bindingKey = node.resolveBinding().getKey();
// if (memberBindingKey.equals(bindingKey)) {
// range.set(nameRange(node.getName()));
// return false;
// }
// }
// return true;
// }
//
// @Override
// public boolean visit(TypeDeclaration node) {
// if (member instanceof IType) {
// String bindingKey = node.resolveBinding().getKey();
// if (memberBindingKey.equals(bindingKey)) {
// range.set(nameRange(node.getName()));
// return false;
// }
// }
// return true;
// }
//
// });
return range.get();
});
if (r == null) {

View File

@@ -18,7 +18,8 @@ import org.springframework.ide.vscode.boot.java.utils.ORCompilationUnitCache;
import org.springframework.ide.vscode.commons.java.IJavaModuleData;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.util.text.Region;
import reactor.util.function.Tuple2;
/**
* VSCode specific source links implementation
@@ -40,10 +41,10 @@ public class VSCodeSourceLinks extends AbstractSourceLinks {
@Override
protected String positionLink(CompilationUnit cu, String fqName) {
if (cu != null) {
Region region = findTypeRegion(cu, fqName);
Tuple2<Integer, Integer> region = findTypeRegion(cu, fqName);
if (region != null) {
int column = cu.getColumnNumber(region.getOffset());
int line = cu.getLineNumber(region.getOffset());
int column = region.getT2();
int line = region.getT1();
StringBuilder sb = new StringBuilder();
sb.append('#');
sb.append(line);

View File

@@ -12,13 +12,14 @@ package org.springframework.ide.vscode.boot.java.scope;
import java.util.Collection;
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.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.Annotation;
import org.openrewrite.java.tree.J.Assignment;
import org.openrewrite.java.tree.J.Empty;
import org.openrewrite.java.tree.J.Literal;
import org.openrewrite.marker.Range;
import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider;
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.util.text.IDocument;
@@ -28,15 +29,15 @@ import org.springframework.ide.vscode.commons.util.text.IDocument;
public class ScopeCompletionProcessor implements CompletionProvider {
@Override
public void provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type,
public void provideCompletions(J node, Annotation annotation,
int offset, IDocument doc, Collection<ICompletionProposal> completions) {
try {
if (node instanceof SimpleName && node.getParent() instanceof MemberValuePair) {
MemberValuePair memberPair = (MemberValuePair) node.getParent();
if (node instanceof Assignment) {
Assignment assignment = (Assignment) node;
// case: @Scope(value=<*>)
if ("value".equals(memberPair.getName().toString()) && memberPair.getValue().toString().equals("$missing$")) {
if ("value".equals(assignment.getVariable().toString()) && assignment.getAssignment() == null) {
for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, offset, offset, "");
completions.add(proposal);
@@ -44,33 +45,38 @@ public class ScopeCompletionProcessor implements CompletionProvider {
}
}
// case: @Scope(<*>)
else if (node == annotation && doc.get(offset - 1, 2).endsWith("()")) {
else if (node instanceof Empty && ORAstUtils.getParent(node) == annotation) {
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());
else if (node instanceof Literal && ORAstUtils.getParent(node) == annotation) {
String nodeStr = node.printTrimmed();
if (nodeStr.startsWith("\"") && nodeStr.endsWith("\"")) {
// case: @Scope("...")
Range range = node.getMarkers().findFirst(Range.class).orElseThrow();
String prefix = doc.get(range.getStart().getOffset(), offset - range.getStart().getOffset());
for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
if (completion.getValue().startsWith(prefix)) {
ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, node.getStartPosition(), node.getStartPosition() + node.getLength(), prefix);
ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, range.getStart().getOffset(), range.getStart().getOffset() + range.length(), 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());
// case: @Scope(value=<*>)
else if (node instanceof Literal && ORAstUtils.getParent(node) instanceof Assignment) {
Assignment assignment = (Assignment) ORAstUtils.getParent(node);
String nodeStr = node.printTrimmed();
if ("value".equals(assignment.getVariable().printTrimmed()) && nodeStr.startsWith("\"") && nodeStr.endsWith("\"")) {
Range range = node.getMarkers().findFirst(Range.class).orElseThrow();
String prefix = doc.get(range.getStart().getOffset(), offset - range.getStart().getOffset());
for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
if (completion.getValue().startsWith(prefix)) {
ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, node.getStartPosition(), node.getStartPosition() + node.getLength(), prefix);
ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, range.getStart().getOffset(), range.getStart().getOffset() + range.length(), prefix);
completions.add(proposal);
}
}
@@ -83,7 +89,7 @@ public class ScopeCompletionProcessor implements CompletionProvider {
}
@Override
public void provideCompletions(ASTNode node, int offset, IDocument doc, Collection<ICompletionProposal> completions) {
public void provideCompletions(J node, int offset, IDocument doc, Collection<ICompletionProposal> completions) {
}
}

View File

@@ -13,9 +13,9 @@ package org.springframework.ide.vscode.boot.java.snippets;
import java.util.List;
import java.util.Optional;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.lsp4j.CompletionItemKind;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.CompilationUnit;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.languageserver.util.SnippetBuilder;
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
@@ -45,7 +45,7 @@ public class JavaSnippet {
}
public Optional<ICompletionProposal> generateCompletion(Supplier<SnippetBuilder> snippetBuilderFactory,
DocumentRegion query, ASTNode node, CompilationUnit cu) {
DocumentRegion query, J node, CompilationUnit cu) {
if (context.appliesTo(node)) {
return Optional.of(

View File

@@ -10,21 +10,39 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.snippets;
import java.util.List;
import java.util.Optional;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.lsp4j.CompletionItemKind;
import org.springframework.ide.vscode.boot.java.jdt.imports.ImportRewrite;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.Result;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.J.CompilationUnit;
import org.openrewrite.java.tree.JavaSourceFile;
import org.openrewrite.shaded.jgit.diff.Edit;
import org.openrewrite.shaded.jgit.diff.EditList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.java.utils.JGitUtils;
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.util.SnippetBuilder;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.Renderable;
import org.springframework.ide.vscode.commons.util.Renderables;
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.LanguageId;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import com.google.common.base.Supplier;
public class JavaSnippetCompletion implements ICompletionProposal{
private static final Logger log = LoggerFactory.getLogger(JavaSnippetCompletion.class);
private DocumentRegion query;
private JavaSnippet javaSnippet;
@@ -65,17 +83,69 @@ public class JavaSnippetCompletion implements ICompletionProposal{
@Override
public Optional<DocumentEdits> getAdditionalEdit() {
ImportRewrite rewrite = ImportRewrite.create(cu, true);
javaSnippet.getImports().ifPresent((imprts ->
{
for (String imprt : imprts) {
rewrite.addImport(imprt);
Recipe r = new Recipe() {
@Override
public String getDisplayName() {
return "Add Imports";
}
}));
@Override
protected TreeVisitor<?, ExecutionContext> getVisitor() {
return new JavaIsoVisitor<>() {
public JavaSourceFile visitJavaSourceFile(JavaSourceFile cu, ExecutionContext p) {
javaSnippet.getImports().ifPresent(imports -> imports.forEach(i -> maybeAddImport(i)));
return cu;
};
};
}
};
List<Result> results = r.run(List.of(cu));
if (!results.isEmpty()) {
Result result = results.get(0);
TextDocument newDoc = new TextDocument(null, LanguageId.PLAINTEXT, 0, result.getAfter().printAll());
DocumentEdits edit = rewrite.createEdit(query.getDocument());
return edit != null ? Optional.of(edit) : Optional.empty();
EditList diff = JGitUtils.getDiff(result.getBefore().printAll(), newDoc.get());
if (!diff.isEmpty()) {
IDocument doc = query.getDocument();
DocumentEdits edits = new DocumentEdits(doc, false);
for (Edit e : diff) {
try {
switch(e.getType()) {
case DELETE:
edits.delete(doc.getLineOffset(e.getBeginA()), getStartOfLine(doc, e.getEndA()));
break;
case INSERT:
edits.insert(doc.getLineOffset(e.getBeginA()), newDoc.textBetween(newDoc.getLineOfOffset(e.getBeginB()), getStartOfLine(newDoc, e.getEndB())));
break;
case REPLACE:
edits.replace(doc.getLineOfOffset(e.getBeginA()), getStartOfLine(doc, e.getEndA()), newDoc.textBetween(newDoc.getLineOfOffset(e.getBeginB()), getStartOfLine(newDoc, e.getEndB())));
break;
case EMPTY:
break;
}
} catch (BadLocationException ex) {
log.error("Diff conversion failed", ex);
}
}
return Optional.of(edits);
}
}
return Optional.empty();
}
private static int getStartOfLine(IDocument doc, int lineNumber) {
IRegion lineInformation = doc.getLineInformation(lineNumber);
if (lineInformation != null) {
return lineInformation.getOffset();
}
if (lineNumber > 0) {
IRegion currentLine = doc.getLineInformation(lineNumber - 1);
return currentLine.getOffset() + currentLine.getLength();
}
return 0;
}
}

View File

@@ -10,11 +10,11 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.snippets;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.ClassDeclaration;
public interface JavaSnippetContext {
JavaSnippetContext BOOT_MEMBERS = (node) -> node instanceof TypeDeclaration;
JavaSnippetContext BOOT_MEMBERS = (node) -> node instanceof ClassDeclaration;
boolean appliesTo(ASTNode node);
boolean appliesTo(J node);
}

View File

@@ -14,8 +14,8 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.CompilationUnit;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.languageserver.util.PrefixFinder;
import org.springframework.ide.vscode.commons.languageserver.util.SnippetBuilder;
@@ -47,7 +47,7 @@ public class JavaSnippetManager {
}
public void getCompletions(IDocument doc, int offset, ASTNode node, CompilationUnit cu, Collection<ICompletionProposal> completions) {
public void getCompletions(IDocument doc, int offset, J node, CompilationUnit cu, Collection<ICompletionProposal> completions) {
DocumentRegion query = PREFIX_FINDER.getPrefixRegion(doc, offset);
for (JavaSnippet javaSnippet : snippets) {

View File

@@ -0,0 +1,20 @@
package org.springframework.ide.vscode.boot.java.utils;
import java.nio.charset.StandardCharsets;
import org.openrewrite.shaded.jgit.diff.EditList;
import org.openrewrite.shaded.jgit.diff.HistogramDiff;
import org.openrewrite.shaded.jgit.diff.RawText;
import org.openrewrite.shaded.jgit.diff.RawTextComparator;
public class JGitUtils {
public static EditList getDiff(String txt1, String txt2) {
RawText rt1 = new RawText(txt1.getBytes(StandardCharsets.UTF_8));
RawText rt2 = new RawText(txt2.getBytes(StandardCharsets.UTF_8));
EditList diffList = new EditList();
diffList.addAll(new HistogramDiff().diff(RawTextComparator.DEFAULT, rt1, rt2));
return diffList;
}
}

View File

@@ -0,0 +1,104 @@
package org.springframework.ide.vscode.boot.java.utils;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import org.openrewrite.Cursor;
import org.openrewrite.SourceFile;
import org.openrewrite.Tree;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.CompilationUnit;
import org.openrewrite.marker.Marker;
import org.openrewrite.marker.Range;
public class ORAstUtils {
private static class AncestersMarker implements Marker {
private UUID uuid;
private List<J> ancesters = List.of();
public AncestersMarker(List<J> ancesters) {
this.uuid = Tree.randomId();
this.ancesters = ancesters;
}
@Override
public UUID getId() {
return uuid;
}
@SuppressWarnings("unchecked")
public <T> T getFirstAnsector(Class<T> clazz) {
if (ancesters != null) {
for (J node : ancesters) {
if (clazz.isInstance(node)) {
return (T) node;
}
}
}
return null;
}
public J getParent() {
if (ancesters != null && !ancesters.isEmpty()) {
return ancesters.get(0);
}
return null;
}
}
public static J findAstNodeAt(CompilationUnit cu, int offset) {
AtomicReference<J> f = new AtomicReference<>();
new JavaIsoVisitor<AtomicReference<J>>() {
public J visit(Tree tree, AtomicReference<J> found) {
if (tree == null) {
return null;
}
if (found.get() == null && tree instanceof J) {
J node = (J) tree;
Range range = node.getMarkers().findFirst(Range.class).orElse(null);
if (range != null
&& range.getStart().getOffset() <= offset
&& offset <= range.getEnd().getOffset()) {
super.visit(tree, found);
if (found.get() == null) {
List<J> ancesters = new ArrayList<>();
for (Cursor c = getCursor(); c != null && !(c.getValue() instanceof SourceFile); c = c.getParent()) {
Object o = c.getValue();
if (o instanceof J) {
ancesters.add((J) o);
}
}
J n = node.withMarkers(node.getMarkers().addIfAbsent(new AncestersMarker(ancesters)));
found.set(n);
return n;
}
} else {
return (J) tree;
}
}
return (J) tree;
};
}.visitNonNull(cu, f);
return f.get();
}
@SuppressWarnings("unchecked")
public static <T> T findNode(J node, Class<T> clazz) {
if (clazz.isInstance(node)) {
return (T) node;
}
AncestersMarker ancestry = node.getMarkers().findFirst(AncestersMarker.class).orElseThrow();
return ancestry.getFirstAnsector(clazz);
}
public static J getParent(J node) {
AncestersMarker ancestry = node.getMarkers().findFirst(AncestersMarker.class).orElseThrow();
return ancestry.getParent();
}
}

View File

@@ -3,7 +3,9 @@ package org.springframework.ide.vscode.boot.java.utils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -11,6 +13,7 @@ import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.io.IOUtils;
@@ -118,22 +121,27 @@ public class ORCompilationUnitCache implements DocumentContentProvider, Disposab
private JavaParser loadJavaParser(IJavaProject project) {
try {
return javaParsers.get(project, () -> JavaParser.fromJavaVersion().classpath(getClasspathEntries(project)).build());
return javaParsers.get(project, () -> {
List<Path> classpath = getClasspathEntries(project).stream().map(s -> new File(s).toPath()).collect(Collectors.toList());
JavaParser jp = JavaParser.fromJavaVersion().build();
jp.setClasspath(classpath);
return jp;
});
} catch (ExecutionException e) {
logger.error("{}", e);
return null;
}
}
private static String[] getClasspathEntries(IJavaProject project) throws Exception {
private static Set<String> getClasspathEntries(IJavaProject project) throws Exception {
if (project == null) {
return new String[0];
return Collections.emptySet();
} else {
IClasspath classpath = project.getClasspath();
Stream<File> classpathEntries = IClasspathUtil.getAllBinaryRoots(classpath).stream();
return classpathEntries
.filter(file -> file.exists())
.map(file -> file.getAbsolutePath()).toArray(String[]::new);
.map(file -> file.getAbsolutePath()).collect(Collectors.toSet());
}
}
@@ -200,7 +208,8 @@ public class ORCompilationUnitCache implements DocumentContentProvider, Disposab
}
});
Result result = new UpdateSourcePositions().run(javaParser.parseInputs(List.of(input), null, new InMemoryExecutionContext())).get(0);
List<CompilationUnit> parseInputs = javaParser.parseInputs(List.of(input), null, new InMemoryExecutionContext());
Result result = new UpdateSourcePositions().run(parseInputs).get(0);
logger.info("CU Cache: created new AST for {}", uri.toString());
@@ -234,5 +243,26 @@ public class ORCompilationUnitCache implements DocumentContentProvider, Disposab
return requestor.apply(null);
}
/**
* Never research shows at the AST is thread-safe when used in read-only mode:
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=58314
*
* This means that the previous implemented synchronization around the requestor
* working on the AST is not necessary as long as the requestor operates in read-only
* mode on the AST nodes.
*
* Warning: Callers should take care to do all AST processing inside of the requestor callback and
* not pass of AST nodes to helper functions that work aynchronously or store AST nodes or ITypeBindings
* for later use. The JDT ASTs are not thread safe!
*/
@Deprecated
public <T> T withCompilationUnit(TextDocument document, Function<CompilationUnit, T> requestor) {
IJavaProject project = this.projectFinder != null ? projectFinder.find(document.getId()).orElse(null) : null;
URI uri = URI.create(document.getUri());
return withCompilationUnit(project, uri, requestor);
}
}

View File

@@ -19,12 +19,13 @@ import java.util.Optional;
import java.util.Set;
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.eclipse.lsp4j.TextDocumentIdentifier;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.Annotation;
import org.openrewrite.marker.Range;
import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider;
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.PropertyInfo;
@@ -54,7 +55,7 @@ public class ValueCompletionProcessor implements CompletionProvider {
}
@Override
public void provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type,
public void provideCompletions(J node, Annotation annotation,
int offset, IDocument doc, Collection<ICompletionProposal> completions) {
try {
@@ -75,28 +76,29 @@ public class ValueCompletionProcessor implements CompletionProvider {
completions.add(proposal);
}
}
// TODO: Get these cases fixed for OR AST
// case: @Value(prefix<*>)
else if (node instanceof SimpleName && node.getParent() instanceof Annotation) {
computeProposalsForSimpleName(node, completions, offset, doc);
}
// case: @Value(value=<*>)
else if (node instanceof SimpleName && node.getParent() instanceof MemberValuePair
&& "value".equals(((MemberValuePair)node.getParent()).getName().toString())) {
computeProposalsForSimpleName(node, completions, offset, doc);
}
// case: @Value("prefix<*>")
else if (node instanceof StringLiteral && node.getParent() instanceof Annotation) {
if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
computeProposalsForStringLiteral(node, completions, offset, doc);
}
}
// case: @Value(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(node, completions, offset, doc);
}
}
// else if (node instanceof SimpleName && node.getParent() instanceof Annotation) {
// computeProposalsForSimpleName(node, completions, offset, doc);
// }
// // case: @Value(value=<*>)
// else if (node instanceof SimpleName && node.getParent() instanceof MemberValuePair
// && "value".equals(((MemberValuePair)node.getParent()).getName().toString())) {
// computeProposalsForSimpleName(node, completions, offset, doc);
// }
// // case: @Value("prefix<*>")
// else if (node instanceof StringLiteral && node.getParent() instanceof Annotation) {
// if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
// computeProposalsForStringLiteral(node, completions, offset, doc);
// }
// }
// // case: @Value(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(node, completions, offset, doc);
// }
// }
}
catch (Exception e) {
e.printStackTrace();
@@ -104,7 +106,7 @@ public class ValueCompletionProcessor implements CompletionProvider {
}
@Override
public void provideCompletions(ASTNode node, int offset, IDocument doc, Collection<ICompletionProposal> completions) {
public void provideCompletions(J node, int offset, IDocument doc, Collection<ICompletionProposal> completions) {
}
private void computeProposalsForSimpleName(ASTNode node, Collection<ICompletionProposal> completions, int offset,
@@ -130,14 +132,17 @@ public class ValueCompletionProcessor implements CompletionProvider {
}
}
private void computeProposalsForStringLiteral(ASTNode node, Collection<ICompletionProposal> completions, int offset,
private void computeProposalsForStringLiteral(J node, Collection<ICompletionProposal> completions, int offset,
IDocument doc) throws BadLocationException {
String prefix = identifyPropertyPrefix(doc.get(node.getStartPosition() + 1, offset - (node.getStartPosition() + 1)), offset - (node.getStartPosition() + 1));
Range r = node.getMarkers().findFirst(Range.class).orElseThrow();
int nodeStartOffset = r.getStart().getOffset();
int nodeLength = r.length();
String prefix = identifyPropertyPrefix(doc.get(nodeStartOffset + 1, offset - (nodeStartOffset + 1)), offset - (nodeStartOffset + 1));
int startOffset = offset - prefix.length();
int endOffset = offset;
String prePrefix = doc.get(node.getStartPosition() + 1, offset - prefix.length() - node.getStartPosition() - 1);
String prePrefix = doc.get(nodeStartOffset + 1, offset - prefix.length() - nodeStartOffset - 1);
String preCompletion;
if (prePrefix.endsWith("${")) {
@@ -150,7 +155,7 @@ public class ValueCompletionProcessor implements CompletionProvider {
preCompletion = "${";
}
String fullNodeContent = doc.get(node.getStartPosition(), node.getLength());
String fullNodeContent = doc.get(nodeStartOffset, nodeLength);
String postCompletion = isClosingBracketMissing(fullNodeContent + preCompletion) ? "}" : "";
List<Match<PropertyInfo>> matches = findMatches(prefix, doc);

View File

@@ -17,7 +17,7 @@ import org.springframework.ide.vscode.boot.app.BootLanguageServerParams;
import org.springframework.ide.vscode.boot.editor.harness.PropertyIndexHarness;
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
import org.springframework.ide.vscode.boot.java.links.VSCodeSourceLinks;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.boot.java.utils.ORCompilationUnitCache;
import org.springframework.ide.vscode.boot.java.utils.SymbolCache;
import org.springframework.ide.vscode.boot.java.utils.SymbolCacheVoid;
import org.springframework.ide.vscode.boot.java.utils.test.MockProjectObserver;
@@ -65,7 +65,7 @@ public class SourceLinksTestConf {
return (DefaultSpringPropertyIndexProvider) serverParams.indexProvider;
}
@Bean SourceLinks sourceLinks(CompilationUnitCache cuCache, JavaProjectFinder projectFinder) {
@Bean SourceLinks sourceLinks(ORCompilationUnitCache cuCache, JavaProjectFinder projectFinder) {
return new VSCodeSourceLinks(cuCache, projectFinder);
}

View File

@@ -67,6 +67,19 @@ public class ScopeCompletionTest {
"@Scope(\"websocket\"<*>)");
}
@Test
public void testBracketsWithSpacesInsideCompletion() throws Exception {
prepareCase("@Scope(\"onClass\")", "@Scope( <*>)");
assertAnnotationCompletions(
"@Scope( \"application\"<*>)",
"@Scope( \"globalSession\"<*>)",
"@Scope( \"prototype\"<*>)",
"@Scope( \"request\"<*>)",
"@Scope( \"session\"<*>)",
"@Scope( \"singleton\"<*>)",
"@Scope( \"websocket\"<*>)");
}
@Test
public void testEmptyStringLiteralCompletion() throws Exception {
prepareCase("@Scope(\"onClass\")", "@Scope(\"<*>\")");

View File

@@ -24,7 +24,7 @@ import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.gradle.internal.impldep.com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.springframework.ide.vscode.boot.java.links.VSCodeSourceLinks;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.boot.java.utils.ORCompilationUnitCache;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.javadoc.JavaDocProviders;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
@@ -61,7 +61,7 @@ public class VSCodeSourceLinksTest {
@Test
public void testJavaSourceUrl() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app");
Optional<String> url = new VSCodeSourceLinks(new CompilationUnitCache(null, null, null), null).sourceLinkUrlForFQName(project, "com.example.EmptyBoot15WebAppApplication");
Optional<String> url = new VSCodeSourceLinks(new ORCompilationUnitCache(null, null, null), null).sourceLinkUrlForFQName(project, "com.example.EmptyBoot15WebAppApplication");
assertTrue(url.isPresent());
Path projectPath = Paths.get(project.pom().getParent());
URI uri = URI.create(url.get());
@@ -78,7 +78,7 @@ public class VSCodeSourceLinksTest {
@Test
public void testClasspathResourceOnTomcatUrl() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app");
Optional<String> url = new VSCodeSourceLinks(new CompilationUnitCache(null, null, null), new JavaProjectFinder() {
Optional<String> url = new VSCodeSourceLinks(new ORCompilationUnitCache(null, null, null), new JavaProjectFinder() {
@Override
public Optional<IJavaProject> find(TextDocumentIdentifier doc) {
@@ -107,7 +107,7 @@ public class VSCodeSourceLinksTest {
@Test
public void testJarUrl() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app");
Optional<String> url = new VSCodeSourceLinks(new CompilationUnitCache(null, null, null), null).sourceLinkUrlForFQName(project, "org.springframework.boot.autoconfigure.SpringBootApplication");
Optional<String> url = new VSCodeSourceLinks(new ORCompilationUnitCache(null, null, null), null).sourceLinkUrlForFQName(project, "org.springframework.boot.autoconfigure.SpringBootApplication");
assertTrue(url.isPresent());
String headerPart = url.get().substring(0, url.get().indexOf('?'));
assertEquals("jdt://contents/spring-boot-autoconfigure-1.5.8.RELEASE.jar/org.springframework.boot.autoconfigure/SpringBootApplication.class", headerPart);
@@ -118,7 +118,7 @@ public class VSCodeSourceLinksTest {
@Test
public void testJarUrlInnerType() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app");
Optional<String> url = new VSCodeSourceLinks(new CompilationUnitCache(null, null, null), null).sourceLinkUrlForFQName(project, "org.springframework.web.client.RestTemplate$AcceptHeaderRequestCallback");
Optional<String> url = new VSCodeSourceLinks(new ORCompilationUnitCache(null, null, null), null).sourceLinkUrlForFQName(project, "org.springframework.web.client.RestTemplate$AcceptHeaderRequestCallback");
assertTrue(url.isPresent());
String headerPart = url.get().substring(0, url.get().indexOf('?'));
assertEquals("jdt://contents/spring-web-4.3.12.RELEASE.jar/org.springframework.web.client/RestTemplate$AcceptHeaderRequestCallback.class", headerPart);