PT #165911996: Switch to LocationLink from Location for definitions

This commit is contained in:
BoykoAlex
2019-10-04 18:34:09 -04:00
parent 2e73b4b66f
commit bb79221cfe
18 changed files with 228 additions and 113 deletions

View File

@@ -51,6 +51,7 @@ import org.eclipse.lsp4j.CodeLens;
import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.MarkupContent; import org.eclipse.lsp4j.MarkupContent;
import org.eclipse.lsp4j.MarkupKind; import org.eclipse.lsp4j.MarkupKind;
import org.eclipse.lsp4j.Range;
import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IEditorReference;
@@ -466,6 +467,9 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
if (project != null) { if (project != null) {
Location location = new Location(); Location location = new Location();
location.setUri(Utils.eclipseIntroUri(project.getElementName(), params.getBindingKey()).toString()); location.setUri(Utils.eclipseIntroUri(project.getElementName(), params.getBindingKey()).toString());
// Set the range because LocationLink needs it to be non-null. The target range
// would highlighted by the eclipse intro URL navigation anyway
location.setRange(new Range());
return location; return location;
} }
} }

View File

@@ -15,14 +15,18 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentPositionParams; import org.eclipse.lsp4j.TextDocumentPositionParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.commons.languageserver.definition.SimpleDefinitionFinder; import org.springframework.ide.vscode.commons.languageserver.definition.SimpleDefinitionFinder;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.text.TextDocument; import org.springframework.ide.vscode.commons.util.text.TextDocument;
import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil; import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil;
import org.springframework.ide.vscode.commons.yaml.ast.YamlAstCache; import org.springframework.ide.vscode.commons.yaml.ast.YamlAstCache;
@@ -34,9 +38,9 @@ import org.yaml.snakeyaml.nodes.Node;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.ImmutableList.Builder;
import reactor.core.publisher.Flux;
public class BoshDefintionFinder extends SimpleDefinitionFinder<SimpleLanguageServer> { public class BoshDefintionFinder extends SimpleDefinitionFinder<SimpleLanguageServer> {
private static final Logger log = LoggerFactory.getLogger(BoshDefintionFinder.class);
//TODO: lots of common code between BoshDefintionFinder and ConcourseDefinitionFinder. //TODO: lots of common code between BoshDefintionFinder and ConcourseDefinitionFinder.
// should be possible to pull up into a common super class. // should be possible to pull up into a common super class.
@@ -69,7 +73,7 @@ public class BoshDefintionFinder extends SimpleDefinitionFinder<SimpleLanguageSe
} }
@Override @Override
public List<Location> handle(TextDocumentPositionParams params) { public List<LocationLink> handle(TextDocumentPositionParams params) {
try { try {
TextDocument doc = server.getTextDocumentService().get(params); TextDocument doc = server.getTextDocumentService().get(params);
if (doc!=null) { if (doc!=null) {
@@ -81,14 +85,19 @@ public class BoshDefintionFinder extends SimpleDefinitionFinder<SimpleLanguageSe
if (type!=null) { if (type!=null) {
Handler handler = handlers.get(type); Handler handler = handlers.get(type);
if (handler!=null) { if (handler!=null) {
return handler.handle(refNode, doc, ast); int start = refNode.getStartMark().getIndex();
int end = refNode.getEndMark().getIndex();
Range originalRange = doc.toRange(start, end - start);
return handler.handle(refNode, doc, ast).stream()
.map(l -> new LocationLink(l.getUri(), l.getRange(), l.getRange(), originalRange))
.collect(Collectors.toList());
} }
} }
} }
} }
} }
} catch (Exception e) { } catch (Exception e) {
Log.log(e); log.error("", e);;
} }
return ImmutableList.of(); return ImmutableList.of();
} }
@@ -129,7 +138,7 @@ public class BoshDefintionFinder extends SimpleDefinitionFinder<SimpleLanguageSe
try { try {
return Optional.of(new Location(doc.getUri(), doc.toRange(start, end-start))); return Optional.of(new Location(doc.getUri(), doc.toRange(start, end-start)));
} catch (BadLocationException e) { } catch (BadLocationException e) {
Log.log(e); log.error("", e);;
return Optional.empty(); return Optional.empty();
} }
} }

View File

@@ -41,7 +41,6 @@ import org.springframework.ide.vscode.bosh.models.ReleaseData;
import org.springframework.ide.vscode.bosh.models.ReleasesModel; import org.springframework.ide.vscode.bosh.models.ReleasesModel;
import org.springframework.ide.vscode.bosh.models.StemcellData; import org.springframework.ide.vscode.bosh.models.StemcellData;
import org.springframework.ide.vscode.bosh.models.StemcellsModel; import org.springframework.ide.vscode.bosh.models.StemcellsModel;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.util.ExternalCommand; import org.springframework.ide.vscode.commons.util.ExternalCommand;
import org.springframework.ide.vscode.commons.util.text.LanguageId; import org.springframework.ide.vscode.commons.util.text.LanguageId;
import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems; import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems;
@@ -1587,7 +1586,8 @@ public class BoshEditorTest {
"- name: some-release\n" "- name: some-release\n"
, ,
"some-release" "some-release"
) ),
editor.rangeOf("- release: some-release", "some-release")
); );
} }
@@ -1612,7 +1612,8 @@ public class BoshEditorTest {
editor.assertGotoDefinition( editor.assertGotoDefinition(
editor.positionOf("stemcell: windoze", "windoze"), editor.positionOf("stemcell: windoze", "windoze"),
editor.rangeOf("- alias: windoze", "windoze") editor.rangeOf("- alias: windoze", "windoze"),
editor.rangeOf("stemcell: windoze", "windoze")
); );
} }

View File

@@ -13,11 +13,13 @@ package org.springframework.ide.vscode.commons.languageserver.definition;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentPositionParams; import org.eclipse.lsp4j.TextDocumentPositionParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.commons.languageserver.util.DefinitionHandler; import org.springframework.ide.vscode.commons.languageserver.util.DefinitionHandler;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.text.TextDocument; import org.springframework.ide.vscode.commons.util.text.TextDocument;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@@ -27,6 +29,8 @@ import com.google.common.collect.ImmutableList;
* @author Kris De Volder * @author Kris De Volder
*/ */
public class SimpleDefinitionFinder<T extends SimpleLanguageServer> implements DefinitionHandler { public class SimpleDefinitionFinder<T extends SimpleLanguageServer> implements DefinitionHandler {
private static final Logger log = LoggerFactory.getLogger(SimpleDefinitionFinder.class);
protected final T server; protected final T server;
@@ -35,7 +39,7 @@ public class SimpleDefinitionFinder<T extends SimpleLanguageServer> implements D
} }
@Override @Override
public List<Location> handle(TextDocumentPositionParams params) { public List<LocationLink> handle(TextDocumentPositionParams params) {
try { try {
TextDocument doc = server.getTextDocumentService().get(params); TextDocument doc = server.getTextDocumentService().get(params);
if (doc != null) { if (doc != null) {
@@ -50,19 +54,18 @@ public class SimpleDefinitionFinder<T extends SimpleLanguageServer> implements D
end++; end++;
} }
String word = doc.textBetween(start, end); String word = doc.textBetween(start, end);
Log.log("Looking for definition of '"+word+"'");
String text = doc.get(); String text = doc.get();
int def = text.indexOf(word); int def = text.indexOf(word);
if (def>=0) { if (def>=0) {
Location loc = new Location(params.getTextDocument().getUri(), Range targetRange = doc.toRange(def, word.length());
doc.toRange(def, word.length()) LocationLink link = new LocationLink(params.getTextDocument().getUri(),
targetRange, targetRange, doc.toRange(start, end - start)
); );
Log.log("definition: "+loc); return ImmutableList.of(link);
return ImmutableList.of(loc);
} }
} }
} catch (Exception e) { } catch (Exception e) {
Log.log(e); log.error("", e);
} }
return Collections.emptyList(); return Collections.emptyList();
} }

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2017, 2018 Pivotal, Inc. * Copyright (c) 2017, 2019 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@@ -12,10 +12,10 @@ package org.springframework.ide.vscode.commons.languageserver.util;
import java.util.List; import java.util.List;
import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.TextDocumentPositionParams; import org.eclipse.lsp4j.TextDocumentPositionParams;
@FunctionalInterface @FunctionalInterface
public interface DefinitionHandler { public interface DefinitionHandler {
List<Location> handle(TextDocumentPositionParams position); List<LocationLink> handle(TextDocumentPositionParams position);
} }

View File

@@ -361,12 +361,12 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
DefinitionHandler h = this.definitionHandler; DefinitionHandler h = this.definitionHandler;
if (h != null) { if (h != null) {
return async.invoke(() -> { return async.invoke(() -> {
List<Location> locations = h.handle(position); List<LocationLink> locations = h.handle(position);
if (locations==null) { if (locations==null) {
// vscode client does not like to recieve null result. See: https://github.com/spring-projects/sts4/issues/309 // vscode client does not like to recieve null result. See: https://github.com/spring-projects/sts4/issues/309
locations = ImmutableList.of(); locations = ImmutableList.of();
} }
return Either.forLeft(locations); return Either.forRight(locations);
}); });
} }
return CompletableFuture.completedFuture(Either.forLeft(ImmutableList.of())); return CompletableFuture.completedFuture(Either.forLeft(ImmutableList.of()));

View File

@@ -39,7 +39,7 @@ import org.eclipse.lsp4j.CompletionList;
import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.DocumentSymbol; import org.eclipse.lsp4j.DocumentSymbol;
import org.eclipse.lsp4j.Hover; import org.eclipse.lsp4j.Hover;
import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.MarkedString; import org.eclipse.lsp4j.MarkedString;
import org.eclipse.lsp4j.MarkupContent; import org.eclipse.lsp4j.MarkupContent;
import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Position;
@@ -745,7 +745,7 @@ public class Editor {
return "Editor(\n"+getText()+"\n)"; return "Editor(\n"+getText()+"\n)";
} }
public void assertLinkTargets(String hoverOver, Set<Location> expectedLocations) throws Exception { public void assertLinkTargets(String hoverOver, Set<LocationLink> expectedLocations) throws Exception {
int pos = getRawText().indexOf(hoverOver); int pos = getRawText().indexOf(hoverOver);
if (pos>=0) { if (pos>=0) {
pos += hoverOver.length() / 2; pos += hoverOver.length() / 2;
@@ -753,7 +753,7 @@ public class Editor {
assertTrue("Not found in editor: '"+hoverOver+"'", pos>=0); assertTrue("Not found in editor: '"+hoverOver+"'", pos>=0);
TextDocumentPositionParams params = new TextDocumentPositionParams(new TextDocumentIdentifier(getUri()), doc.toPosition(pos)); TextDocumentPositionParams params = new TextDocumentPositionParams(new TextDocumentIdentifier(getUri()), doc.toPosition(pos));
List<? extends Location> definitions = harness.getDefinitions(params); List<? extends LocationLink> definitions = harness.getDefinitions(params);
assertEquals(ImmutableSet.copyOf(expectedLocations), ImmutableSet.copyOf(definitions)); assertEquals(ImmutableSet.copyOf(expectedLocations), ImmutableSet.copyOf(definitions));
} }
@@ -766,7 +766,7 @@ public class Editor {
assertTrue("Not found in editor: '"+hoverOver+"'", pos>=0); assertTrue("Not found in editor: '"+hoverOver+"'", pos>=0);
TextDocumentPositionParams params = new TextDocumentPositionParams(new TextDocumentIdentifier(getUri()), doc.toPosition(pos)); TextDocumentPositionParams params = new TextDocumentPositionParams(new TextDocumentIdentifier(getUri()), doc.toPosition(pos));
List<? extends Location> definitions = harness.getDefinitions(params); List<? extends LocationLink> definitions = harness.getDefinitions(params);
assertTrue(definitions == null || definitions.isEmpty()); assertTrue(definitions == null || definitions.isEmpty());
} }
@@ -822,12 +822,12 @@ public class Editor {
ignoredTypes.add(type.toString()); ignoredTypes.add(type.toString());
} }
public void assertGotoDefinition(Position pos, Range expectedTarget) throws Exception { public void assertGotoDefinition(Position pos, Range expectedTarget, Range highlightRange) throws Exception {
TextDocumentIdentifier textDocumentId = doc.getId(); TextDocumentIdentifier textDocumentId = doc.getId();
TextDocumentPositionParams params = new TextDocumentPositionParams(textDocumentId, textDocumentId.getUri(), pos); TextDocumentPositionParams params = new TextDocumentPositionParams(textDocumentId, textDocumentId.getUri(), pos);
List<? extends Location> defs = harness.getDefinitions(params); List<? extends LocationLink> defs = harness.getDefinitions(params);
assertEquals(1, defs.size()); assertEquals(1, defs.size());
assertEquals(new Location(textDocumentId.getUri(), expectedTarget), defs.get(0)); assertEquals(new LocationLink(textDocumentId.getUri(), expectedTarget, expectedTarget, highlightRange), defs.get(0));
} }
/** /**

View File

@@ -35,7 +35,6 @@ import java.util.Map.Entry;
import java.util.Random; import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@@ -75,6 +74,7 @@ import org.eclipse.lsp4j.Hover;
import org.eclipse.lsp4j.InitializeParams; import org.eclipse.lsp4j.InitializeParams;
import org.eclipse.lsp4j.InitializeResult; import org.eclipse.lsp4j.InitializeResult;
import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.MarkupContent; import org.eclipse.lsp4j.MarkupContent;
import org.eclipse.lsp4j.MessageActionItem; import org.eclipse.lsp4j.MessageActionItem;
import org.eclipse.lsp4j.MessageParams; import org.eclipse.lsp4j.MessageParams;
@@ -107,7 +107,6 @@ import org.springframework.ide.vscode.commons.languageserver.completion.Document
import org.springframework.ide.vscode.commons.languageserver.util.LanguageServerTestListener; import org.springframework.ide.vscode.commons.languageserver.util.LanguageServerTestListener;
import org.springframework.ide.vscode.commons.languageserver.util.Settings; import org.springframework.ide.vscode.commons.languageserver.util.Settings;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.languageserver.util.WorkspaceSymbolHandler;
import org.springframework.ide.vscode.commons.protocol.CursorMovement; import org.springframework.ide.vscode.commons.protocol.CursorMovement;
import org.springframework.ide.vscode.commons.protocol.HighlightParams; import org.springframework.ide.vscode.commons.protocol.HighlightParams;
import org.springframework.ide.vscode.commons.protocol.ProgressParams; import org.springframework.ide.vscode.commons.protocol.ProgressParams;
@@ -727,9 +726,9 @@ public class LanguageServerHarness {
assertEquals(expected, completion.getLabel()); assertEquals(expected, completion.getLabel());
} }
public List<? extends Location> getDefinitions(TextDocumentPositionParams params) throws Exception { public List<? extends LocationLink> getDefinitions(TextDocumentPositionParams params) throws Exception {
waitForReconcile(); //goto definitions relies on reconciler infos! Must wait or race condition breaking tests occasionally. waitForReconcile(); //goto definitions relies on reconciler infos! Must wait or race condition breaking tests occasionally.
return getServer().getTextDocumentService().definition(params).get().getLeft(); return getServer().getTextDocumentService().definition(params).get().getRight();
} }
public static void assertDocumentation(String expected, CompletionItem completion) { public static void assertDocumentation(String expected, CompletionItem completion) {

View File

@@ -14,13 +14,17 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentPositionParams; import org.eclipse.lsp4j.TextDocumentPositionParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.commons.languageserver.definition.SimpleDefinitionFinder; import org.springframework.ide.vscode.commons.languageserver.definition.SimpleDefinitionFinder;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.text.TextDocument; import org.springframework.ide.vscode.commons.util.text.TextDocument;
import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil; import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil;
import org.springframework.ide.vscode.commons.yaml.ast.YamlAstCache; import org.springframework.ide.vscode.commons.yaml.ast.YamlAstCache;
@@ -34,6 +38,8 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.ImmutableList.Builder;
public class ConcourseDefinitionFinder extends SimpleDefinitionFinder<SimpleLanguageServer> { public class ConcourseDefinitionFinder extends SimpleDefinitionFinder<SimpleLanguageServer> {
private static final Logger log = LoggerFactory.getLogger(ConcourseDefinitionFinder.class);
@FunctionalInterface @FunctionalInterface
private interface Handler { private interface Handler {
@@ -84,7 +90,7 @@ public class ConcourseDefinitionFinder extends SimpleDefinitionFinder<SimpleLang
} }
@Override @Override
public List<Location> handle(TextDocumentPositionParams params) { public List<LocationLink> handle(TextDocumentPositionParams params) {
try { try {
TextDocument doc = server.getTextDocumentService().get(params); TextDocument doc = server.getTextDocumentService().get(params);
if (doc!=null) { if (doc!=null) {
@@ -96,14 +102,19 @@ public class ConcourseDefinitionFinder extends SimpleDefinitionFinder<SimpleLang
if (type!=null) { if (type!=null) {
Handler handler = handlers.get(type); Handler handler = handlers.get(type);
if (handler!=null) { if (handler!=null) {
return handler.handle(refNode, doc, ast); int start = refNode.getStartMark().getIndex();
int end = refNode.getEndMark().getIndex();
Range originalRange = doc.toRange(start, end - start);
return handler.handle(refNode, doc, ast).stream()
.map(l -> new LocationLink(l.getUri(), l.getRange(), l.getRange(), originalRange))
.collect(Collectors.toList());
} }
} }
} }
} }
} }
} catch (Exception e) { } catch (Exception e) {
Log.log(e); log.error("", e);;
} }
return ImmutableList.of(); return ImmutableList.of();
} }
@@ -114,7 +125,7 @@ public class ConcourseDefinitionFinder extends SimpleDefinitionFinder<SimpleLang
try { try {
return Optional.of(new Location(doc.getUri(), doc.toRange(start, end-start))); return Optional.of(new Location(doc.getUri(), doc.toRange(start, end-start)));
} catch (BadLocationException e) { } catch (BadLocationException e) {
Log.log(e); log.error("", e);;
return Optional.empty(); return Optional.empty();
} }
} }

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2016 Pivotal, Inc. * Copyright (c) 2016, 2019 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@@ -46,7 +46,6 @@ import org.springframework.ide.vscode.languageserver.testharness.CodeAction;
import org.springframework.ide.vscode.languageserver.testharness.Editor; import org.springframework.ide.vscode.languageserver.testharness.Editor;
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness; import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
import org.springframework.ide.vscode.languageserver.testharness.SynchronizationPoint; import org.springframework.ide.vscode.languageserver.testharness.SynchronizationPoint;
import org.springframework.test.annotation.Repeat;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@@ -3161,7 +3160,8 @@ public class ConcourseEditorTest {
); );
editor.assertGotoDefinition(editor.positionOf("get: my-git", "my-git"), editor.assertGotoDefinition(editor.positionOf("get: my-git", "my-git"),
editor.rangeOf("- name: my-git", "my-git") editor.rangeOf("- name: my-git", "my-git"),
editor.rangeOf("get: my-git", "my-git")
); );
} }
@@ -3184,7 +3184,8 @@ public class ConcourseEditorTest {
" - prepare-stuff\n" " - prepare-stuff\n"
); );
editor.assertGotoDefinition(editor.positionOf("- prepare-stuff", "prepare-stuff"), editor.assertGotoDefinition(editor.positionOf("- prepare-stuff", "prepare-stuff"),
editor.rangeOf("- name: prepare-stuff", "prepare-stuff") editor.rangeOf("- name: prepare-stuff", "prepare-stuff"),
editor.rangeOf("- prepare-stuff", "prepare-stuff")
); );
} }
@@ -3199,7 +3200,8 @@ public class ConcourseEditorTest {
" type: slack-notification\n" " type: slack-notification\n"
); );
editor.assertGotoDefinition(editor.positionOf("type: slack-notification", "slack-notification"), editor.assertGotoDefinition(editor.positionOf("type: slack-notification", "slack-notification"),
editor.rangeOf("- name: slack-notification", "slack-notification") editor.rangeOf("- name: slack-notification", "slack-notification"),
editor.rangeOf("type: slack-notification", "slack-notification")
); );
} }

View File

@@ -12,10 +12,14 @@ package org.springframework.ide.vscode.boot.app;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentPositionParams; import org.eclipse.lsp4j.TextDocumentPositionParams;
import org.gradle.internal.impldep.com.google.common.collect.ImmutableList; import org.gradle.internal.impldep.com.google.common.collect.ImmutableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ide.vscode.boot.java.links.JavaElementLocationProvider; import org.springframework.ide.vscode.boot.java.links.JavaElementLocationProvider;
import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.java.links.SourceLinks;
@@ -40,6 +44,8 @@ import org.springframework.stereotype.Component;
@Component @Component
public class PropertiesJavaDefinitionHandler implements DefinitionHandler, LanguageSpecific { public class PropertiesJavaDefinitionHandler implements DefinitionHandler, LanguageSpecific {
private static final Logger log = LoggerFactory.getLogger(PropertiesJavaDefinitionHandler.class);
@Autowired @Autowired
private SimpleTextDocumentService documents; private SimpleTextDocumentService documents;
@@ -54,7 +60,7 @@ public class PropertiesJavaDefinitionHandler implements DefinitionHandler, Langu
private BootLanguageServerParams params; private BootLanguageServerParams params;
@Override @Override
public List<Location> handle(TextDocumentPositionParams position) { public List<LocationLink> handle(TextDocumentPositionParams position) {
try { try {
TextDocument doc = documents.get(position); TextDocument doc = documents.get(position);
TypeUtil typeUtil = params.typeUtilProvider.getTypeUtil(sourceLinks, doc); TypeUtil typeUtil = params.typeUtilProvider.getTypeUtil(sourceLinks, doc);
@@ -67,24 +73,57 @@ public class PropertiesJavaDefinitionHandler implements DefinitionHandler, Langu
} }
} }
private List<Location> getDefinitions(FuzzyMap<PropertyInfo> index, TypeUtil typeUtil, TextDocument doc, int offset) { private List<LocationLink> getDefinitions(FuzzyMap<PropertyInfo> index, TypeUtil typeUtil, TextDocument doc, int offset) {
IJavaProject project = typeUtil.getJavaProject(); IJavaProject project = typeUtil.getJavaProject();
PropertyFinder propertyFinder = new PropertyFinder(index, typeUtil, doc, offset); PropertyFinder propertyFinder = new PropertyFinder(index, typeUtil, doc, offset);
Node node = propertyFinder.findNode(); Node node = propertyFinder.findNode();
if (node instanceof Key) { try {
Collection<IMember> propertyJavaElements = PropertiesDefinitionCalculator.getPropertyJavaElements(typeUtil, propertyFinder, project, ((Key) node).decode()); Range selectionRange = doc.toRange(node.getOffset(), node.getLength());
return PropertiesDefinitionCalculator.getLocations(javaElementLocationProvider, project, propertyJavaElements); if (node instanceof Key) {
} else if (node instanceof Value) { String propertyKey = ((Key) node).decode();
Value value = (Value) node; Collection<IMember> propertyJavaElements = PropertiesDefinitionCalculator.getPropertyJavaElements(typeUtil, propertyFinder, project, propertyKey);
Key key = value.getParent().getKey();
Type type = PropertiesDefinitionCalculator.getPropertyType(propertyFinder, key.decode()); // Attempt to highlight only chunk of the key for which definition is found
if (type != null) { Range range = adjustedHighlightRangeForKey(doc, selectionRange, propertyFinder.findBestHoverMatch(propertyKey));
return PropertiesDefinitionCalculator.getValueDefinitionLocations(javaElementLocationProvider, typeUtil, type, value.decode()); return PropertiesDefinitionCalculator.getLocations(javaElementLocationProvider, project, propertyJavaElements).stream()
.map(l -> new LocationLink(l.getUri(), l.getRange(), l.getRange(), range))
.collect(Collectors.toList());
} else if (node instanceof Value) {
Value value = (Value) node;
Key key = value.getParent().getKey();
Type type = PropertiesDefinitionCalculator.getPropertyType(propertyFinder, key.decode());
if (type != null) {
// Trim spaces from the value node text
Range range = trimHighlightRange(selectionRange, doc);
return PropertiesDefinitionCalculator.getValueDefinitionLocations(javaElementLocationProvider, typeUtil, type, value.decode()).stream()
.map(l -> new LocationLink(l.getUri(), l.getRange(), l.getRange(), range))
.collect(Collectors.toList());
}
} }
} catch (BadLocationException e) {
log.error("", e);
} }
return ImmutableList.of(); return ImmutableList.of();
} }
private Range adjustedHighlightRangeForKey(TextDocument doc, Range range, PropertyInfo propertyInfo) throws BadLocationException {
Range adjustedRange = trimHighlightRange(range, doc);
int start = doc.toOffset(range.getStart());
String id = propertyInfo.getId();
if (id.equals(doc.get(start, id.length()))) {
adjustedRange.setEnd(doc.toPosition(start + id.length()));
}
return adjustedRange;
}
private Range trimHighlightRange(Range range, TextDocument doc) throws BadLocationException {
int start = doc.toOffset(range.getStart());
for (; start < doc.getLength() && Character.isWhitespace(doc.getChar(start)); start++) {}
int end = start;
for (; end < doc.getLength() && !Character.isWhitespace(doc.getChar(end)); end++) {}
return doc.toRange(start, end - start);
}
@Override @Override
public Collection<LanguageId> supportedLanguages() { public Collection<LanguageId> supportedLanguages() {
return ImmutableList.of(LanguageId.BOOT_PROPERTIES); return ImmutableList.of(LanguageId.BOOT_PROPERTIES);

View File

@@ -48,6 +48,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.TextDocumentPositionParams; import org.eclipse.lsp4j.TextDocumentPositionParams;
import org.eclipse.lsp4xml.dom.DOMAttr; import org.eclipse.lsp4xml.dom.DOMAttr;
import org.eclipse.lsp4xml.dom.DOMDocument; import org.eclipse.lsp4xml.dom.DOMDocument;
@@ -139,7 +140,7 @@ public class XmlBeansConfigDefinitionHandler implements DefinitionHandler, Langu
} }
@Override @Override
public List<Location> handle(TextDocumentPositionParams position) { public List<LocationLink> handle(TextDocumentPositionParams position) {
try { try {
if (config.isSpringXMLSupportEnabled() && config.areXmlHyperlinksEnabled()) { if (config.isSpringXMLSupportEnabled() && config.areXmlHyperlinksEnabled()) {
TextDocument doc = documents.get(position); TextDocument doc = documents.get(position);
@@ -175,11 +176,15 @@ public class XmlBeansConfigDefinitionHandler implements DefinitionHandler, Langu
List<? extends XMLHyperlinkProvider> providers = hyperlinkProviders.get(key); List<? extends XMLHyperlinkProvider> providers = hyperlinkProviders.get(key);
if (providers != null) { if (providers != null) {
ImmutableList.Builder<Location> listBuilder = ImmutableList.builder(); ImmutableList.Builder<LocationLink> listBuilder = ImmutableList.builder();
for (XMLHyperlinkProvider provider : providers) { for (XMLHyperlinkProvider provider : providers) {
Location location = provider.getDefinition(doc, namespace, node, attributeAt); Location location = provider.getDefinition(doc, namespace, node, attributeAt);
if (location != null) { if (location != null) {
listBuilder.add(location); int start = attributeAt.getNodeAttrValue().getStart() + 1;
int end = attributeAt.getNodeAttrValue().getEnd() - 1;
listBuilder.add(new LocationLink(location.getUri(),
location.getRange(), location.getRange(),
doc.toRange(start, Math.max(0, end - start))));
} }
} }
return listBuilder.build(); return listBuilder.build();

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc. * Copyright (c) 2018, 2019 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@@ -12,8 +12,10 @@ package org.springframework.ide.vscode.boot.app;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentPositionParams; import org.eclipse.lsp4j.TextDocumentPositionParams;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -65,7 +67,7 @@ public class YamlPropertiesJavaDefinitionHandler implements DefinitionHandler, L
} }
@Override @Override
public List<Location> handle(TextDocumentPositionParams position) { public List<LocationLink> handle(TextDocumentPositionParams position) {
try { try {
TextDocument doc = documents.get(position); TextDocument doc = documents.get(position);
int offset = doc.toOffset(position.getPosition()); int offset = doc.toOffset(position.getPosition());
@@ -90,13 +92,21 @@ public class YamlPropertiesJavaDefinitionHandler implements DefinitionHandler, L
assistContext = assistPath.traverse(assistContext); assistContext = assistPath.traverse(assistContext);
if (assistContext != null) { if (assistContext != null) {
Node node = astPath.get(astPath.size() - 1).get();
int start = node.getStartMark().getIndex();
int end = node.getEndMark().getIndex();
Range originalRange = doc.toRange(start, end - start);
if (path.pointsAtValue()) { if (path.pointsAtValue()) {
DocumentRegion nodeRegion = getNodeRegion(ast, offset); DocumentRegion nodeRegion = getNodeRegion(ast, offset);
if (nodeRegion != null) { if (nodeRegion != null) {
return assistContext.getDefinitionsForPropertyValue(nodeRegion); return assistContext.getDefinitionsForPropertyValue(nodeRegion).stream()
.map(l -> new LocationLink(l.getUri(), l.getRange(), l.getRange(), originalRange))
.collect(Collectors.toList());
} }
} else { } else {
return assistContext.getDefinitionsForPropertyKey(); return assistContext.getDefinitionsForPropertyKey().stream()
.map(l -> new LocationLink(l.getUri(), l.getRange(), l.getRange(), originalRange))
.collect(Collectors.toList());
} }
} }
} }

View File

@@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.java.links;
import java.net.URI; import java.net.URI;
import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.Range;
import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.IMember; import org.springframework.ide.vscode.commons.java.IMember;
@@ -26,6 +27,7 @@ public class EclipseJavaElementLocationProvider implements JavaElementLocationPr
} else { } else {
Location location = new Location(); Location location = new Location();
location.setUri(uri.toString()); location.setUri(uri.toString());
location.setRange(new Range());
return location; return location;
} }
} }

View File

@@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.lsp4j.DidChangeConfigurationParams; import org.eclipse.lsp4j.DidChangeConfigurationParams;
import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.Range;
import org.junit.Before; import org.junit.Before;
@@ -95,7 +96,7 @@ public class XmlBeansHyperlinkTest {
"</beans>\n", "</beans>\n",
UriUtil.toUri(xmlFilePath.toFile()).toString() UriUtil.toUri(xmlFilePath.toFile()).toString()
); );
definitionLinkAsserts.assertLinkTargets(editor, "u.t.r.SimpleObj", project, "u.t.r.SimpleObj"); definitionLinkAsserts.assertLinkTargets(editor, "u.t.r.SimpleObj", project, editor.rangeOf("u.t.r.SimpleObj", "u.t.r.SimpleObj"), "u.t.r.SimpleObj");
} }
@Test @Test
@@ -113,7 +114,9 @@ public class XmlBeansHyperlinkTest {
"</beans>\n", "</beans>\n",
UriUtil.toUri(xmlFilePath.toFile()).toString() UriUtil.toUri(xmlFilePath.toFile()).toString()
); );
definitionLinkAsserts.assertLinkTargets(editor, "age", project, DefinitionLinkAsserts.method("u.t.r.TestBean", "setAge", "int")); definitionLinkAsserts.assertLinkTargets(editor, "age", project,
editor.rangeOf("<property name=\"age\" value=\"10\" />", "age"),
DefinitionLinkAsserts.method("u.t.r.TestBean", "setAge", "int"));
} }
@Test @Test
@@ -131,7 +134,9 @@ public class XmlBeansHyperlinkTest {
"</beans>\n", "</beans>\n",
UriUtil.toUri(xmlFilePath.toFile()).toString() UriUtil.toUri(xmlFilePath.toFile()).toString()
); );
definitionLinkAsserts.assertLinkTargets(editor, "message", project, DefinitionLinkAsserts.method("u.t.r.SuperTestBean", "setMessage", "java.lang.String")); definitionLinkAsserts.assertLinkTargets(editor, "message", project,
editor.rangeOf("<property name=\"message\" value=\"Hello\" />", "message"),
DefinitionLinkAsserts.method("u.t.r.SuperTestBean", "setMessage", "java.lang.String"));
} }
@Test @Test
@@ -150,9 +155,13 @@ public class XmlBeansHyperlinkTest {
UriUtil.toUri(xmlFilePath.toFile()).toString() UriUtil.toUri(xmlFilePath.toFile()).toString()
); );
Path rootContextFilePath = Paths.get(project.getLocationUri()).resolve("src/main/webapp/WEB-INF/spring/root-context.xml"); Path rootContextFilePath = Paths.get(project.getLocationUri()).resolve("src/main/webapp/WEB-INF/spring/root-context.xml");
Location expectedLocation = new Location(); Range targetRange = new Range(new Position(6,7), new Position(6, 21));
expectedLocation.setUri(UriUtil.toUri(rootContextFilePath.toFile()).toString()); LocationLink expectedLocation = new LocationLink(
expectedLocation.setRange(new Range(new Position(6,7), new Position(6, 21))); UriUtil.toUri(rootContextFilePath.toFile()).toString(),
targetRange,
targetRange,
editor.rangeOf("name=\"simple\" ref=\"simpleObj\"", "simpleObj")
);
editor.assertLinkTargets("simpleObj", Collections.singleton(expectedLocation)); editor.assertLinkTargets("simpleObj", Collections.singleton(expectedLocation));
} }
@@ -216,9 +225,13 @@ public class XmlBeansHyperlinkTest {
UriUtil.toUri(xmlFilePath.toFile()).toString() UriUtil.toUri(xmlFilePath.toFile()).toString()
); );
Path rootContextFilePath = Paths.get(project.getLocationUri()).resolve("src/main/webapp/WEB-INF/spring/root-context.xml"); Path rootContextFilePath = Paths.get(project.getLocationUri()).resolve("src/main/webapp/WEB-INF/spring/root-context.xml");
Location expectedLocation = new Location(); Range targetRange = new Range(new Position(6,7), new Position(6, 21));
expectedLocation.setUri(UriUtil.toUri(rootContextFilePath.toFile()).toString()); LocationLink expectedLocation = new LocationLink(
expectedLocation.setRange(new Range(new Position(6,7), new Position(6, 21))); UriUtil.toUri(rootContextFilePath.toFile()).toString(),
targetRange,
targetRange,
editor.rangeOf("name=\"simple\" ref=\"simpleObj\"", "simpleObj")
);
editor.assertLinkTargets("simpleObj", Collections.singleton(expectedLocation)); editor.assertLinkTargets("simpleObj", Collections.singleton(expectedLocation));
} }

View File

@@ -395,16 +395,17 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
"flyway.init-sqls=a,b,c\n" "flyway.init-sqls=a,b,c\n"
); );
definitionLinkAsserts.assertLinkTargets(editor, "server", p, definitionLinkAsserts.assertLinkTargets(editor, "server", p, editor.rangeOf("server.port", "server.port"),
method("org.springframework.boot.autoconfigure.web.ServerProperties", "setPort", "java.lang.Integer")); method("org.springframework.boot.autoconfigure.web.ServerProperties", "setPort", "java.lang.Integer"));
definitionLinkAsserts.assertLinkTargets(editor, "data", p, definitionLinkAsserts.assertLinkTargets(editor, "data", p, editor.rangeOf("spring.datasource.login-timeout", "spring.datasource.login-timeout"),
method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "hikariDataSource"), method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "hikariDataSource"),
method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "tomcatDataSource"), method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "tomcatDataSource"),
method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "dbcpDataSource") method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "dbcpDataSource")
); );
definitionLinkAsserts.assertLinkTargets(editor, "flyway", p, method("org.springframework.boot.autoconfigure.flyway.FlywayProperties", "setInitSqls", "java.util.List")); definitionLinkAsserts.assertLinkTargets(editor, "flyway", p, editor.rangeOf("flyway.init-sqls", "flyway.init-sqls"),
method("org.springframework.boot.autoconfigure.flyway.FlywayProperties", "setInitSqls", "java.util.List"));
System.out.println("<<< testHyperlinkTargets"); System.out.println("<<< testHyperlinkTargets");
} }
@@ -420,7 +421,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
"logging.level.com.acme=INFO\n" "logging.level.com.acme=INFO\n"
); );
definitionLinkAsserts.assertLinkTargets(editor, "level", p, "org.springframework.boot.logging.LoggingApplicationListener"); definitionLinkAsserts.assertLinkTargets(editor, "level", p, editor.rangeOf("logging.level", "logging.level"),
"org.springframework.boot.logging.LoggingApplicationListener");
System.out.println("<<< testHyperlinkTargetsLoggingLevel"); System.out.println("<<< testHyperlinkTargetsLoggingLevel");
} }
@@ -1642,7 +1644,9 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
"spring.data.mongodb.field-naming-strategy=org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy\n" + "spring.data.mongodb.field-naming-strategy=org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy\n" +
"#more stuff" "#more stuff"
); );
definitionLinkAsserts.assertLinkTargets(editor, "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy", project, "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy"); definitionLinkAsserts.assertLinkTargets(editor, "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy", project,
editor.rangeOf("org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy", "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy"),
"org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy");
//Linking should also work for types that aren't valid based on the constraints //Linking should also work for types that aren't valid based on the constraints
@@ -1653,7 +1657,9 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
"spring.data.mongodb.field-naming-strategy=java.lang.String\n" + "spring.data.mongodb.field-naming-strategy=java.lang.String\n" +
"#more stuff" "#more stuff"
); );
definitionLinkAsserts.assertLinkTargets(editor, "java.lang.String", project, "java.lang.String"); definitionLinkAsserts.assertLinkTargets(editor, "java.lang.String", project,
editor.rangeOf("java.lang.String", "java.lang.String"),
"java.lang.String");
// Instead of java.lang.String // Instead of java.lang.String
editor = newEditor( editor = newEditor(
@@ -1661,7 +1667,9 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
"spring.data.mongodb.field-naming-strategy=org.springframework.core.io.Resource\n" + "spring.data.mongodb.field-naming-strategy=org.springframework.core.io.Resource\n" +
"#more stuff" "#more stuff"
); );
definitionLinkAsserts.assertLinkTargets(editor, "org.springframework.core.io.Resource", project, "org.springframework.core.io.Resource"); definitionLinkAsserts.assertLinkTargets(editor, "org.springframework.core.io.Resource", project,
editor.rangeOf("org.springframework.core.io.Resource", "org.springframework.core.io.Resource"),
"org.springframework.core.io.Resource");
} }
@@ -1834,12 +1842,12 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
editor = newEditor( editor = newEditor(
"my.background: RED" "my.background: RED"
); );
definitionLinkAsserts.assertLinkTargets(editor, "RED", project, field("demo.Color", "RED")); definitionLinkAsserts.assertLinkTargets(editor, "RED", project, editor.rangeOf("RED", "RED"), field("demo.Color", "RED"));
editor = newEditor( editor = newEditor(
"my.background=red" "my.background=red"
); );
definitionLinkAsserts.assertLinkTargets(editor, "red", project, field("demo.Color", "RED")); definitionLinkAsserts.assertLinkTargets(editor, "red", project, editor.rangeOf("red", "red"), field("demo.Color", "RED"));
} }
@Test public void testEnumInPojoField() throws Exception { @Test public void testEnumInPojoField() throws Exception {
@@ -1851,8 +1859,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
editor = newEditor( editor = newEditor(
"my.screen.background=green" "my.screen.background=green"
); );
definitionLinkAsserts.assertLinkTargets(editor, "background", project, method("com.example.demo.MyProperties$Screen", "getScreen")); definitionLinkAsserts.assertLinkTargets(editor, "background", project, editor.rangeOf("my.screen.background", "my.screen.background"), method("com.example.demo.MyProperties$Screen", "getScreen"));
definitionLinkAsserts.assertLinkTargets(editor, "green", project, field("com.example.demo.Color", "GREEN")); definitionLinkAsserts.assertLinkTargets(editor, "green", project, editor.rangeOf("green", "green"), field("com.example.demo.Color", "GREEN"));
} }
@Test public void testNoHoverForUnrecognizedProperty() throws Exception { @Test public void testNoHoverForUnrecognizedProperty() throws Exception {

View File

@@ -26,7 +26,6 @@ import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
@@ -631,8 +630,8 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
" getter-only: getme\n" " getter-only: getme\n"
); );
definitionLinkAsserts.assertLinkTargets(editor, "data", project, method("demo.FooProperties", "setData", "demo.ColorData")); definitionLinkAsserts.assertLinkTargets(editor, "data", project, editor.rangeOf("data:", "data"), method("demo.FooProperties", "setData", "demo.ColorData"));
definitionLinkAsserts.assertLinkTargets(editor, "wavelen", project, method("demo.ColorData", "setWavelen", "double")); definitionLinkAsserts.assertLinkTargets(editor, "wavelen", project, editor.rangeOf("wavelen:", "wavelen"), method("demo.ColorData", "setWavelen", "double"));
} }
@Test @Test
@@ -653,11 +652,11 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
//io.spring.initializr.metadata.DefaultMetadataElement.setDefault(boolean) //io.spring.initializr.metadata.DefaultMetadataElement.setDefault(boolean)
//io.spring.initializr.metadata.MetadataElement.setId(String) //io.spring.initializr.metadata.MetadataElement.setId(String)
//io.spring.initializr.metadata.MetadataElement.setName(String) //io.spring.initializr.metadata.MetadataElement.setName(String)
definitionLinkAsserts.assertLinkTargets(editor, "name", project, method("io.spring.initializr.metadata.MetadataElement", "setName", "java.lang.String")); definitionLinkAsserts.assertLinkTargets(editor, "name", project, editor.rangeOf("name:", "name"), method("io.spring.initializr.metadata.MetadataElement", "setName", "java.lang.String"));
definitionLinkAsserts.assertLinkTargets(editor, "id", project, method("io.spring.initializr.metadata.MetadataElement", "setId", "java.lang.String")); definitionLinkAsserts.assertLinkTargets(editor, "id", project, editor.rangeOf("id:", "id"), method("io.spring.initializr.metadata.MetadataElement", "setId", "java.lang.String"));
definitionLinkAsserts.assertLinkTargets(editor, "default", project, method("io.spring.initializr.metadata.DefaultMetadataElement", "setDefault", "boolean")); definitionLinkAsserts.assertLinkTargets(editor, "default", project, editor.rangeOf("default:", "default"), method("io.spring.initializr.metadata.DefaultMetadataElement", "setDefault", "boolean"));
definitionLinkAsserts.assertLinkTargets(editor, "bogus", project /*NONE*/); definitionLinkAsserts.assertLinkTargets(editor, "bogus", project, editor.rangeOf("bogus", "bogus") /*NONE*/);
} }
@Test public void testHyperlinkTargets() throws Exception { @Test public void testHyperlinkTargets() throws Exception {
@@ -675,14 +674,17 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
); );
definitionLinkAsserts.assertLinkTargets(editor, "port", p, definitionLinkAsserts.assertLinkTargets(editor, "port", p,
editor.rangeOf("port", "port"),
method("org.springframework.boot.autoconfigure.web.ServerProperties", "setPort", "java.lang.Integer") method("org.springframework.boot.autoconfigure.web.ServerProperties", "setPort", "java.lang.Integer")
); );
definitionLinkAsserts.assertLinkTargets(editor, "login-", p, definitionLinkAsserts.assertLinkTargets(editor, "login-", p,
editor.rangeOf("login-timeout", "login-timeout"),
method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "hikariDataSource"), method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "hikariDataSource"),
method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "tomcatDataSource"), method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "tomcatDataSource"),
method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "dbcpDataSource") method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "dbcpDataSource")
); );
definitionLinkAsserts.assertLinkTargets(editor, "init-sql", p, definitionLinkAsserts.assertLinkTargets(editor, "init-sql", p,
editor.rangeOf("init-sqls", "init-sqls"),
method("org.springframework.boot.autoconfigure.flyway.FlywayProperties", "setInitSqls", "java.util.List")); method("org.springframework.boot.autoconfigure.flyway.FlywayProperties", "setInitSqls", "java.util.List"));
} }
@@ -3858,7 +3860,9 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
" mongodb:\n" + " mongodb:\n" +
" field-naming-strategy: org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy\n" " field-naming-strategy: org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy\n"
); );
definitionLinkAsserts.assertLinkTargets(editor, "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy", project, "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy"); definitionLinkAsserts.assertLinkTargets(editor, "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy", project,
editor.rangeOf("org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy", "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy"),
"org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy");
editor = newEditor( editor = newEditor(
"spring:\n" + "spring:\n" +
@@ -3867,7 +3871,9 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
" field-naming-strategy:\n" + " field-naming-strategy:\n" +
" org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy\n" " org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy\n"
); );
definitionLinkAsserts.assertLinkTargets(editor, "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy", project, "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy"); definitionLinkAsserts.assertLinkTargets(editor, "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy", project,
editor.rangeOf("org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy", "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy"),
"org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy");
//Linking should also work for types that aren't valid based on the constraints //Linking should also work for types that aren't valid based on the constraints
editor = newEditor( editor = newEditor(
@@ -3877,7 +3883,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
" field-naming-strategy: java.lang.String\n" + " field-naming-strategy: java.lang.String\n" +
"#more stuff" "#more stuff"
); );
definitionLinkAsserts.assertLinkTargets(editor, "java.lang.String", project, "java.lang.String"); definitionLinkAsserts.assertLinkTargets(editor, "java.lang.String", project, editor.rangeOf("java.lang.String", "java.lang.String"), "java.lang.String");
} }
@Test public void test_STS_3335_reconcile_list_nested_in_Map_of_String() throws Exception { @Test public void test_STS_3335_reconcile_list_nested_in_Map_of_String() throws Exception {
@@ -4022,13 +4028,13 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
"my:\n" + "my:\n" +
" background: RED" " background: RED"
); );
definitionLinkAsserts.assertLinkTargets(editor, "RED", project, field("demo.Color", "RED")); definitionLinkAsserts.assertLinkTargets(editor, "RED", project, editor.rangeOf("RED", "RED"), field("demo.Color", "RED"));
editor = newEditor( editor = newEditor(
"my:\n" + "my:\n" +
" background: red" " background: red"
); );
definitionLinkAsserts.assertLinkTargets(editor, "red", project, field("demo.Color", "RED")); definitionLinkAsserts.assertLinkTargets(editor, "red", project, editor.rangeOf("red", "red"), field("demo.Color", "RED"));
} }
@Test public void testHyperLinkEnumValueInMapKey() throws Exception { @Test public void testHyperLinkEnumValueInMapKey() throws Exception {
@@ -4044,8 +4050,8 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
" RED: Rood\n" + " RED: Rood\n" +
" green: Groen\n" " green: Groen\n"
); );
definitionLinkAsserts.assertLinkTargets(editor, "RED", project, field("demo.Color", "RED")); definitionLinkAsserts.assertLinkTargets(editor, "RED", project, editor.rangeOf("RED", "RED"), field("demo.Color", "RED"));
definitionLinkAsserts.assertLinkTargets(editor, "green", project, field("demo.Color", "GREEN")); definitionLinkAsserts.assertLinkTargets(editor, "green", project, editor.rangeOf("green", "green"), field("demo.Color", "GREEN"));
editor = newEditor( editor = newEditor(
"spring:\n" + "spring:\n" +
@@ -4054,6 +4060,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
" INDENT_OUTPUT: true" " INDENT_OUTPUT: true"
); );
definitionLinkAsserts.assertLinkTargets(editor, "INDENT_OUTPUT", project, definitionLinkAsserts.assertLinkTargets(editor, "INDENT_OUTPUT", project,
editor.rangeOf("INDENT_OUTPUT", "INDENT_OUTPUT"),
field("com.fasterxml.jackson.databind.SerializationFeature", "INDENT_OUTPUT") field("com.fasterxml.jackson.databind.SerializationFeature", "INDENT_OUTPUT")
); );
@@ -4064,6 +4071,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
" indent-output: true" " indent-output: true"
); );
definitionLinkAsserts.assertLinkTargets(editor, "indent-output", project, definitionLinkAsserts.assertLinkTargets(editor, "indent-output", project,
editor.rangeOf("indent-output", "indent-output"),
field("com.fasterxml.jackson.databind.SerializationFeature", "INDENT_OUTPUT") field("com.fasterxml.jackson.databind.SerializationFeature", "INDENT_OUTPUT")
); );
} }

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc. * Copyright (c) 2018, 2019 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@@ -27,6 +27,7 @@ import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.Range;
import org.springframework.ide.vscode.boot.java.links.JavaDocumentUriProvider; import org.springframework.ide.vscode.boot.java.links.JavaDocumentUriProvider;
import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.java.links.SourceLinks;
@@ -88,34 +89,34 @@ public class DefinitionLinkAsserts {
} }
public void assertLinkTargets(Editor editor, String hoverOver, IJavaProject project, JavaMethod... methods) throws Exception { public void assertLinkTargets(Editor editor, String hoverOver, IJavaProject project, Range highlightRange, JavaMethod... methods) throws Exception {
Set<Location> expectedLocations = Arrays.stream(methods).map(method -> { Set<LocationLink> expectedLocations = Arrays.stream(methods).map(method -> {
try { try {
return getLocation(project, method); return getLocation(project, method);
} catch (Exception e) { } catch (Exception e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
}).collect(Collectors.toSet()); }).map(l -> new LocationLink(l.getUri(), l.getRange(), l.getRange(), highlightRange)).collect(Collectors.toSet());
editor.assertLinkTargets(hoverOver, expectedLocations); editor.assertLinkTargets(hoverOver, expectedLocations);
} }
public void assertLinkTargets(Editor editor, String hoverOver, IJavaProject project, String typeFqName) throws Exception { public void assertLinkTargets(Editor editor, String hoverOver, IJavaProject project, Range highlightRange, String typeFqName) throws Exception {
Location expectedLocation = getLocation(project, typeFqName); Location l = getLocation(project, typeFqName);
LocationLink link = new LocationLink(l.getUri(), l.getRange(), l.getRange(), highlightRange);
System.out.println("Expected Location: " + expectedLocation); editor.assertLinkTargets(hoverOver, ImmutableSet.of(link));
editor.assertLinkTargets(hoverOver, ImmutableSet.of(expectedLocation));
} }
public void assertLinkTargets(Editor editor, String hoverOver, IJavaProject project, JavaField field) throws Exception { public void assertLinkTargets(Editor editor, String hoverOver, IJavaProject project, Range highlightRange, JavaField field) throws Exception {
Location expectedLocation = getLocation(project, field); Location l = getLocation(project, field);
System.out.println("Expected Location: " + expectedLocation); LocationLink link = new LocationLink(l.getUri(), l.getRange(), l.getRange(), highlightRange);
editor.assertLinkTargets(hoverOver, ImmutableSet.of(expectedLocation)); editor.assertLinkTargets(hoverOver, ImmutableSet.of(link));
} }
private Location getLocation(IJavaProject project, String fqName) throws Exception { private Location getLocation(IJavaProject project, String fqName) throws Exception {