Make live hovers AnnotationHierarchyAware
This commit is contained in:
@@ -250,7 +250,7 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
|
||||
|
||||
protected BootJavaHoverProvider createHoverHandler(JavaProjectFinder javaProjectFinder,
|
||||
RunningAppProvider runningAppProvider) {
|
||||
HashMap<String, HoverProvider> providers = new HashMap<>();
|
||||
AnnotationHierarchyAwareLookup<HoverProvider> providers = new AnnotationHierarchyAwareLookup<>();
|
||||
|
||||
providers.put(org.springframework.ide.vscode.boot.java.value.Constants.SPRING_VALUE, new ValueHoverProvider());
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ package org.springframework.ide.vscode.boot.java.handlers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -32,6 +33,7 @@ import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.TextDocumentPositionParams;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareLookup;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
@@ -53,10 +55,10 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
|
||||
private JavaProjectFinder projectFinder;
|
||||
private BootJavaLanguageServer server;
|
||||
private Map<String, HoverProvider> hoverProviders;
|
||||
private AnnotationHierarchyAwareLookup<HoverProvider> hoverProviders;
|
||||
private RunningAppProvider runningAppProvider;
|
||||
|
||||
public BootJavaHoverProvider(BootJavaLanguageServer server, JavaProjectFinder projectFinder, Map<String, HoverProvider> specificProviders, RunningAppProvider runningAppProvider) {
|
||||
public BootJavaHoverProvider(BootJavaLanguageServer server, JavaProjectFinder projectFinder, AnnotationHierarchyAwareLookup<HoverProvider> specificProviders, RunningAppProvider runningAppProvider) {
|
||||
this.server = server;
|
||||
this.projectFinder = projectFinder;
|
||||
this.hoverProviders = specificProviders;
|
||||
@@ -84,7 +86,7 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
|
||||
public Range[] getLiveHoverHints(final TextDocument document, final SpringBootApp[] runningBootApps) {
|
||||
return server.getCompilationUnitCache().withCompilationUnit(document, cu -> {
|
||||
List<Range> result = new ArrayList<>();
|
||||
Collection<Range> result = new HashSet<>();
|
||||
try {
|
||||
if (cu != null) {
|
||||
cu.accept(new ASTVisitor() {
|
||||
@@ -129,26 +131,22 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
});
|
||||
}
|
||||
|
||||
protected void extractLiveHints(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps, List<Range> result) {
|
||||
protected void extractLiveHints(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps, Collection<Range> result) {
|
||||
ITypeBinding type = annotation.resolveTypeBinding();
|
||||
if (type != null) {
|
||||
String qualifiedName = type.getQualifiedName();
|
||||
if (qualifiedName != null) {
|
||||
HoverProvider provider = this.hoverProviders.get(qualifiedName);
|
||||
if (provider != null) {
|
||||
if (runningApps.length>0) {
|
||||
getProject(doc).ifPresent(project -> {
|
||||
if (hasActuatorDependency(project)) {
|
||||
Collection<Range> hints = provider.getLiveHoverHints(annotation, doc, runningApps);
|
||||
if (hints!=null) {
|
||||
result.addAll(hints);
|
||||
}
|
||||
} else {
|
||||
//Do nothing... we don't want a highlight for the 'no actuator warning'
|
||||
//ASTUtils.nameRange(doc, annotation).ifPresent(result::add);
|
||||
if (runningApps.length>0) {
|
||||
for (HoverProvider provider : this.hoverProviders.get(type)) {
|
||||
getProject(doc).ifPresent(project -> {
|
||||
if (hasActuatorDependency(project)) {
|
||||
Collection<Range> hints = provider.getLiveHoverHints(annotation, doc, runningApps);
|
||||
if (hints!=null) {
|
||||
result.addAll(hints);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
//Do nothing... we don't want a highlight for the 'no actuator warning'
|
||||
//ASTUtils.nameRange(doc, annotation).ifPresent(result::add);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,20 +177,20 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
annotation = (Annotation) node;
|
||||
ITypeBinding type = annotation.resolveTypeBinding();
|
||||
if (type != null) {
|
||||
String qualifiedName = type.getQualifiedName();
|
||||
if (qualifiedName != null) {
|
||||
HoverProvider provider = this.hoverProviders.get(qualifiedName);
|
||||
if (provider != null) {
|
||||
SpringBootApp[] runningApps = getRunningSpringApps(project);
|
||||
if (runningApps.length>0) {
|
||||
if (hasActuatorDependency(project)) {
|
||||
return provider.provideHover(node, annotation, type, offset, doc, project, runningApps);
|
||||
} else {
|
||||
DocumentRegion region = ASTUtils.nameRegion(doc, annotation);
|
||||
if (region.containsOffset(offset)) {
|
||||
return actuatorWarning(project);
|
||||
}
|
||||
}
|
||||
SpringBootApp[] runningApps = getRunningSpringApps(project);
|
||||
if (runningApps.length>0) {
|
||||
for (HoverProvider provider : this.hoverProviders.get(type)) {
|
||||
Hover hover = provider.provideHover(node, annotation, type, offset, doc, project, runningApps);
|
||||
if (hover!=null) {
|
||||
//TODO: compose multiple hovers somehow instead of just returning the first one?
|
||||
return hover;
|
||||
}
|
||||
}
|
||||
//Only reaching here if we didn't get a hover.
|
||||
if (!hasActuatorDependency(project)) {
|
||||
DocumentRegion region = ASTUtils.nameRegion(doc, annotation);
|
||||
if (region.containsOffset(offset)) {
|
||||
return actuatorWarning(project);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,23 +52,29 @@ public class ActiveProfilesProvider implements HoverProvider {
|
||||
if (runningApps.length>0) {
|
||||
StringBuilder markdown = new StringBuilder();
|
||||
markdown.append("**Active Profiles**\n\n");
|
||||
boolean hasInterestingApp = false;
|
||||
for (SpringBootApp app : runningApps) {
|
||||
List<String> profiles = app.getActiveProfiles();
|
||||
if (profiles==null) {
|
||||
markdown.append(niceAppName(app)+" : _Unknown_\n\n");
|
||||
} else if (profiles.isEmpty()) {
|
||||
markdown.append(niceAppName(app)+" : _None_\n\n");
|
||||
} else {
|
||||
markdown.append(niceAppName(app)+" :\n");
|
||||
for (String profile : profiles) {
|
||||
markdown.append("- "+profile+"\n");
|
||||
hasInterestingApp = true;
|
||||
if (profiles.isEmpty()) {
|
||||
markdown.append(niceAppName(app)+" : _None_\n\n");
|
||||
} else {
|
||||
markdown.append(niceAppName(app)+" :\n");
|
||||
for (String profile : profiles) {
|
||||
markdown.append("- "+profile+"\n");
|
||||
}
|
||||
markdown.append("\n");
|
||||
}
|
||||
markdown.append("\n");
|
||||
}
|
||||
}
|
||||
return new Hover(
|
||||
ImmutableList.of(Either.forLeft(markdown.toString()))
|
||||
);
|
||||
if (hasInterestingApp) {
|
||||
return new Hover(
|
||||
ImmutableList.of(Either.forLeft(markdown.toString()))
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -300,7 +300,7 @@ public class AutowiredHoverProviderTest {
|
||||
);
|
||||
editor.assertHighlights("@Component", "@Autowired", "@Autowired");
|
||||
for (int i = 1; i <= 2; i++) {
|
||||
editor.assertHoverContains("@Autowired", 1,
|
||||
editor.assertHoverContains("@Autowired", i,
|
||||
"Bean [id: defaultFoo, type: `com.example.FooImplementation`] got autowired with:\n" +
|
||||
"\n" +
|
||||
"- Bean: otherBean \n" +
|
||||
@@ -351,15 +351,16 @@ public class AutowiredHoverProviderTest {
|
||||
" \n" +
|
||||
"}"
|
||||
);
|
||||
editor.assertHighlights(/* not yet: "@Controller",*/ "@Autowired");
|
||||
for (int i = 1; i <= 2; i++) {
|
||||
editor.assertHoverContains("@Autowired", 1,
|
||||
"Bean [id: myController, type: `com.example.MyController`] got autowired with:\n" +
|
||||
"\n" +
|
||||
"- Bean: restTemplate \n" +
|
||||
" Type: `org.springframework.web.client.RestTemplate`");
|
||||
}
|
||||
|
||||
editor.assertHighlights("@Controller", "@Autowired");
|
||||
editor.assertHoverContains("@Autowired",
|
||||
"Bean [id: myController, type: `com.example.MyController`] got autowired with:\n" +
|
||||
"\n" +
|
||||
"- Bean: restTemplate \n" +
|
||||
" Type: `org.springframework.web.client.RestTemplate`"
|
||||
);
|
||||
editor.assertHoverContains("@Controller",
|
||||
"**Injection report for Bean [id: myController, type: `com.example.MyController`]**"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ public class ActiveProfilesHoverTest {
|
||||
public void testActiveProfileHover_Unknown() throws Exception {
|
||||
//Sometimes its not possible to determine active profiles for an app (e.g. no actuator dependency).
|
||||
//Make sure we show something sensible
|
||||
harness.useProject(projects.mavenProject("no-actuator-boot-15-web-app"));
|
||||
|
||||
mockAppProvider.builder()
|
||||
.isSpringBootApp(true)
|
||||
@@ -98,8 +99,8 @@ public class ActiveProfilesHoverTest {
|
||||
"\n" +
|
||||
"}"
|
||||
);
|
||||
editor.assertHoverContains("@Profile", "Process [PID=22022, name=`foo.bar.RunningApp`] : _Unknown_");
|
||||
editor.assertHighlights("@Profile");
|
||||
editor.assertHoverContains("@Profile", "Consider adding `spring-boot-actuator` as a dependency");
|
||||
editor.assertHighlights(/*NONE*/);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user