From bb79221cfea0eeb8a475f59a2eeb155202f9b9cd Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Fri, 4 Oct 2019 18:34:09 -0400 Subject: [PATCH] PT #165911996: Switch to LocationLink from Location for definitions --- .../commons/STS4LanguageClientImpl.java | 4 ++ .../ide/vscode/bosh/BoshDefintionFinder.java | 23 +++++-- .../ide/vscode/bosh/BoshEditorTest.java | 7 +- .../definition/SimpleDefinitionFinder.java | 21 +++--- .../util/DefinitionHandler.java | 6 +- .../util/SimpleTextDocumentService.java | 4 +- .../languageserver/testharness/Editor.java | 14 ++-- .../testharness/LanguageServerHarness.java | 7 +- .../concourse/ConcourseDefinitionFinder.java | 21 ++++-- .../vscode/concourse/ConcourseEditorTest.java | 12 ++-- .../app/PropertiesJavaDefinitionHandler.java | 65 +++++++++++++++---- .../app/XmlBeansConfigDefinitionHandler.java | 11 +++- .../YamlPropertiesJavaDefinitionHandler.java | 20 ++++-- .../EclipseJavaElementLocationProvider.java | 2 + .../utils/test/XmlBeansHyperlinkTest.java | 31 ++++++--- .../test/ApplicationPropertiesEditorTest.java | 30 +++++---- .../boot/test/ApplicationYamlEditorTest.java | 36 ++++++---- .../boot/test/DefinitionLinkAsserts.java | 27 ++++---- 18 files changed, 228 insertions(+), 113 deletions(-) diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java index 54a8f07c4..88715a32d 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java @@ -51,6 +51,7 @@ import org.eclipse.lsp4j.CodeLens; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.MarkupContent; import org.eclipse.lsp4j.MarkupKind; +import org.eclipse.lsp4j.Range; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; @@ -466,6 +467,9 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La if (project != null) { Location location = new Location(); 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; } } diff --git a/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshDefintionFinder.java b/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshDefintionFinder.java index 7b4ed8a9e..62d4fe970 100644 --- a/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshDefintionFinder.java +++ b/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshDefintionFinder.java @@ -15,14 +15,18 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.Pair; import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.LocationLink; +import org.eclipse.lsp4j.Range; 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.util.SimpleLanguageServer; 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.yaml.ast.NodeUtil; 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.Builder; -import reactor.core.publisher.Flux; - public class BoshDefintionFinder extends SimpleDefinitionFinder { + + private static final Logger log = LoggerFactory.getLogger(BoshDefintionFinder.class); //TODO: lots of common code between BoshDefintionFinder and ConcourseDefinitionFinder. // should be possible to pull up into a common super class. @@ -69,7 +73,7 @@ public class BoshDefintionFinder extends SimpleDefinitionFinder handle(TextDocumentPositionParams params) { + public List handle(TextDocumentPositionParams params) { try { TextDocument doc = server.getTextDocumentService().get(params); if (doc!=null) { @@ -81,14 +85,19 @@ public class BoshDefintionFinder extends SimpleDefinitionFinder new LocationLink(l.getUri(), l.getRange(), l.getRange(), originalRange)) + .collect(Collectors.toList()); } } } } } } catch (Exception e) { - Log.log(e); + log.error("", e);; } return ImmutableList.of(); } @@ -129,7 +138,7 @@ public class BoshDefintionFinder extends SimpleDefinitionFinder implements DefinitionHandler { + + private static final Logger log = LoggerFactory.getLogger(SimpleDefinitionFinder.class); protected final T server; @@ -35,7 +39,7 @@ public class SimpleDefinitionFinder implements D } @Override - public List handle(TextDocumentPositionParams params) { + public List handle(TextDocumentPositionParams params) { try { TextDocument doc = server.getTextDocumentService().get(params); if (doc != null) { @@ -50,19 +54,18 @@ public class SimpleDefinitionFinder implements D end++; } String word = doc.textBetween(start, end); - Log.log("Looking for definition of '"+word+"'"); String text = doc.get(); int def = text.indexOf(word); if (def>=0) { - Location loc = new Location(params.getTextDocument().getUri(), - doc.toRange(def, word.length()) + Range targetRange = 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(loc); + return ImmutableList.of(link); } } } catch (Exception e) { - Log.log(e); + log.error("", e); } return Collections.emptyList(); } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/DefinitionHandler.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/DefinitionHandler.java index 93d2892e8..a712b5244 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/DefinitionHandler.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/DefinitionHandler.java @@ -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 * are made available under the terms of the Eclipse Public License v1.0 * 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 org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.LocationLink; import org.eclipse.lsp4j.TextDocumentPositionParams; @FunctionalInterface public interface DefinitionHandler { - List handle(TextDocumentPositionParams position); + List handle(TextDocumentPositionParams position); } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java index 81bc8b26d..212d0ec1b 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java @@ -361,12 +361,12 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE DefinitionHandler h = this.definitionHandler; if (h != null) { return async.invoke(() -> { - List locations = h.handle(position); + List locations = h.handle(position); if (locations==null) { // vscode client does not like to recieve null result. See: https://github.com/spring-projects/sts4/issues/309 locations = ImmutableList.of(); } - return Either.forLeft(locations); + return Either.forRight(locations); }); } return CompletableFuture.completedFuture(Either.forLeft(ImmutableList.of())); diff --git a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java index ddbe3a654..caf4673c3 100644 --- a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java +++ b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java @@ -39,7 +39,7 @@ import org.eclipse.lsp4j.CompletionList; import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.DocumentSymbol; import org.eclipse.lsp4j.Hover; -import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.LocationLink; import org.eclipse.lsp4j.MarkedString; import org.eclipse.lsp4j.MarkupContent; import org.eclipse.lsp4j.Position; @@ -745,7 +745,7 @@ public class Editor { return "Editor(\n"+getText()+"\n)"; } - public void assertLinkTargets(String hoverOver, Set expectedLocations) throws Exception { + public void assertLinkTargets(String hoverOver, Set expectedLocations) throws Exception { int pos = getRawText().indexOf(hoverOver); if (pos>=0) { pos += hoverOver.length() / 2; @@ -753,7 +753,7 @@ public class Editor { assertTrue("Not found in editor: '"+hoverOver+"'", pos>=0); TextDocumentPositionParams params = new TextDocumentPositionParams(new TextDocumentIdentifier(getUri()), doc.toPosition(pos)); - List definitions = harness.getDefinitions(params); + List definitions = harness.getDefinitions(params); assertEquals(ImmutableSet.copyOf(expectedLocations), ImmutableSet.copyOf(definitions)); } @@ -766,7 +766,7 @@ public class Editor { assertTrue("Not found in editor: '"+hoverOver+"'", pos>=0); TextDocumentPositionParams params = new TextDocumentPositionParams(new TextDocumentIdentifier(getUri()), doc.toPosition(pos)); - List definitions = harness.getDefinitions(params); + List definitions = harness.getDefinitions(params); assertTrue(definitions == null || definitions.isEmpty()); } @@ -822,12 +822,12 @@ public class Editor { 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(); TextDocumentPositionParams params = new TextDocumentPositionParams(textDocumentId, textDocumentId.getUri(), pos); - List defs = harness.getDefinitions(params); + List defs = harness.getDefinitions(params); assertEquals(1, defs.size()); - assertEquals(new Location(textDocumentId.getUri(), expectedTarget), defs.get(0)); + assertEquals(new LocationLink(textDocumentId.getUri(), expectedTarget, expectedTarget, highlightRange), defs.get(0)); } /** diff --git a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java index 1b94688f3..6661080ff 100644 --- a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java +++ b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java @@ -35,7 +35,6 @@ import java.util.Map.Entry; import java.util.Random; import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -75,6 +74,7 @@ import org.eclipse.lsp4j.Hover; import org.eclipse.lsp4j.InitializeParams; import org.eclipse.lsp4j.InitializeResult; import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.LocationLink; import org.eclipse.lsp4j.MarkupContent; import org.eclipse.lsp4j.MessageActionItem; 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.Settings; 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.HighlightParams; import org.springframework.ide.vscode.commons.protocol.ProgressParams; @@ -727,9 +726,9 @@ public class LanguageServerHarness { assertEquals(expected, completion.getLabel()); } - public List getDefinitions(TextDocumentPositionParams params) throws Exception { + public List getDefinitions(TextDocumentPositionParams params) throws Exception { 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) { diff --git a/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/ConcourseDefinitionFinder.java b/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/ConcourseDefinitionFinder.java index 2fc6ca146..7cb79251b 100644 --- a/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/ConcourseDefinitionFinder.java +++ b/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/ConcourseDefinitionFinder.java @@ -14,13 +14,17 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.languageserver.definition.SimpleDefinitionFinder; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; 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.yaml.ast.NodeUtil; 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; public class ConcourseDefinitionFinder extends SimpleDefinitionFinder { + + private static final Logger log = LoggerFactory.getLogger(ConcourseDefinitionFinder.class); @FunctionalInterface private interface Handler { @@ -84,7 +90,7 @@ public class ConcourseDefinitionFinder extends SimpleDefinitionFinder handle(TextDocumentPositionParams params) { + public List handle(TextDocumentPositionParams params) { try { TextDocument doc = server.getTextDocumentService().get(params); if (doc!=null) { @@ -96,14 +102,19 @@ public class ConcourseDefinitionFinder extends SimpleDefinitionFinder new LocationLink(l.getUri(), l.getRange(), l.getRange(), originalRange)) + .collect(Collectors.toList()); } } } } } } catch (Exception e) { - Log.log(e); + log.error("", e);; } return ImmutableList.of(); } @@ -114,7 +125,7 @@ public class ConcourseDefinitionFinder extends SimpleDefinitionFinder handle(TextDocumentPositionParams position) { + public List handle(TextDocumentPositionParams position) { try { TextDocument doc = documents.get(position); TypeUtil typeUtil = params.typeUtilProvider.getTypeUtil(sourceLinks, doc); @@ -67,24 +73,57 @@ public class PropertiesJavaDefinitionHandler implements DefinitionHandler, Langu } } - private List getDefinitions(FuzzyMap index, TypeUtil typeUtil, TextDocument doc, int offset) { + private List getDefinitions(FuzzyMap index, TypeUtil typeUtil, TextDocument doc, int offset) { IJavaProject project = typeUtil.getJavaProject(); PropertyFinder propertyFinder = new PropertyFinder(index, typeUtil, doc, offset); Node node = propertyFinder.findNode(); - if (node instanceof Key) { - Collection propertyJavaElements = PropertiesDefinitionCalculator.getPropertyJavaElements(typeUtil, propertyFinder, project, ((Key) node).decode()); - return PropertiesDefinitionCalculator.getLocations(javaElementLocationProvider, project, propertyJavaElements); - } else if (node instanceof Value) { - Value value = (Value) node; - Key key = value.getParent().getKey(); - Type type = PropertiesDefinitionCalculator.getPropertyType(propertyFinder, key.decode()); - if (type != null) { - return PropertiesDefinitionCalculator.getValueDefinitionLocations(javaElementLocationProvider, typeUtil, type, value.decode()); + try { + Range selectionRange = doc.toRange(node.getOffset(), node.getLength()); + if (node instanceof Key) { + String propertyKey = ((Key) node).decode(); + Collection propertyJavaElements = PropertiesDefinitionCalculator.getPropertyJavaElements(typeUtil, propertyFinder, project, propertyKey); + + // Attempt to highlight only chunk of the key for which definition is found + Range range = adjustedHighlightRangeForKey(doc, selectionRange, propertyFinder.findBestHoverMatch(propertyKey)); + 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(); } - + + 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 public Collection supportedLanguages() { return ImmutableList.of(LanguageId.BOOT_PROPERTIES); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/XmlBeansConfigDefinitionHandler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/XmlBeansConfigDefinitionHandler.java index 9dbe5e325..e0fcd5bd4 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/XmlBeansConfigDefinitionHandler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/XmlBeansConfigDefinitionHandler.java @@ -48,6 +48,7 @@ import java.util.List; import java.util.Map; import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.LocationLink; import org.eclipse.lsp4j.TextDocumentPositionParams; import org.eclipse.lsp4xml.dom.DOMAttr; import org.eclipse.lsp4xml.dom.DOMDocument; @@ -139,7 +140,7 @@ public class XmlBeansConfigDefinitionHandler implements DefinitionHandler, Langu } @Override - public List handle(TextDocumentPositionParams position) { + public List handle(TextDocumentPositionParams position) { try { if (config.isSpringXMLSupportEnabled() && config.areXmlHyperlinksEnabled()) { TextDocument doc = documents.get(position); @@ -175,11 +176,15 @@ public class XmlBeansConfigDefinitionHandler implements DefinitionHandler, Langu List providers = hyperlinkProviders.get(key); if (providers != null) { - ImmutableList.Builder listBuilder = ImmutableList.builder(); + ImmutableList.Builder listBuilder = ImmutableList.builder(); for (XMLHyperlinkProvider provider : providers) { Location location = provider.getDefinition(doc, namespace, node, attributeAt); 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(); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/YamlPropertiesJavaDefinitionHandler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/YamlPropertiesJavaDefinitionHandler.java index 1819934b5..8e96087aa 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/YamlPropertiesJavaDefinitionHandler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/YamlPropertiesJavaDefinitionHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -12,8 +12,10 @@ package org.springframework.ide.vscode.boot.app; import java.util.Collection; 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.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,7 +67,7 @@ public class YamlPropertiesJavaDefinitionHandler implements DefinitionHandler, L } @Override - public List handle(TextDocumentPositionParams position) { + public List handle(TextDocumentPositionParams position) { try { TextDocument doc = documents.get(position); int offset = doc.toOffset(position.getPosition()); @@ -90,13 +92,21 @@ public class YamlPropertiesJavaDefinitionHandler implements DefinitionHandler, L assistContext = assistPath.traverse(assistContext); 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()) { DocumentRegion nodeRegion = getNodeRegion(ast, offset); 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 { - return assistContext.getDefinitionsForPropertyKey(); + return assistContext.getDefinitionsForPropertyKey().stream() + .map(l -> new LocationLink(l.getUri(), l.getRange(), l.getRange(), originalRange)) + .collect(Collectors.toList()); } } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/EclipseJavaElementLocationProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/EclipseJavaElementLocationProvider.java index 84da4dc0a..7b0cbfc04 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/EclipseJavaElementLocationProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/EclipseJavaElementLocationProvider.java @@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.java.links; import java.net.URI; 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.IMember; @@ -26,6 +27,7 @@ public class EclipseJavaElementLocationProvider implements JavaElementLocationPr } else { Location location = new Location(); location.setUri(uri.toString()); + location.setRange(new Range()); return location; } } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/XmlBeansHyperlinkTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/XmlBeansHyperlinkTest.java index cfabc5130..63dee5c66 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/XmlBeansHyperlinkTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/XmlBeansHyperlinkTest.java @@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit; import org.eclipse.lsp4j.DidChangeConfigurationParams; import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.LocationLink; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; import org.junit.Before; @@ -95,7 +96,7 @@ public class XmlBeansHyperlinkTest { "\n", 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 @@ -113,7 +114,9 @@ public class XmlBeansHyperlinkTest { "\n", 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("", "age"), + DefinitionLinkAsserts.method("u.t.r.TestBean", "setAge", "int")); } @Test @@ -131,7 +134,9 @@ public class XmlBeansHyperlinkTest { "\n", 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("", "message"), + DefinitionLinkAsserts.method("u.t.r.SuperTestBean", "setMessage", "java.lang.String")); } @Test @@ -150,9 +155,13 @@ public class XmlBeansHyperlinkTest { UriUtil.toUri(xmlFilePath.toFile()).toString() ); Path rootContextFilePath = Paths.get(project.getLocationUri()).resolve("src/main/webapp/WEB-INF/spring/root-context.xml"); - Location expectedLocation = new Location(); - expectedLocation.setUri(UriUtil.toUri(rootContextFilePath.toFile()).toString()); - expectedLocation.setRange(new Range(new Position(6,7), new Position(6, 21))); + Range targetRange = new Range(new Position(6,7), new Position(6, 21)); + LocationLink expectedLocation = new LocationLink( + UriUtil.toUri(rootContextFilePath.toFile()).toString(), + targetRange, + targetRange, + editor.rangeOf("name=\"simple\" ref=\"simpleObj\"", "simpleObj") + ); editor.assertLinkTargets("simpleObj", Collections.singleton(expectedLocation)); } @@ -216,9 +225,13 @@ public class XmlBeansHyperlinkTest { UriUtil.toUri(xmlFilePath.toFile()).toString() ); Path rootContextFilePath = Paths.get(project.getLocationUri()).resolve("src/main/webapp/WEB-INF/spring/root-context.xml"); - Location expectedLocation = new Location(); - expectedLocation.setUri(UriUtil.toUri(rootContextFilePath.toFile()).toString()); - expectedLocation.setRange(new Range(new Position(6,7), new Position(6, 21))); + Range targetRange = new Range(new Position(6,7), new Position(6, 21)); + LocationLink expectedLocation = new LocationLink( + UriUtil.toUri(rootContextFilePath.toFile()).toString(), + targetRange, + targetRange, + editor.rangeOf("name=\"simple\" ref=\"simpleObj\"", "simpleObj") + ); editor.assertLinkTargets("simpleObj", Collections.singleton(expectedLocation)); } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java index e4757940a..abc0eead2 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java @@ -395,16 +395,17 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { "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")); - 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", "tomcatDataSource"), 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"); } @@ -420,7 +421,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { "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"); } @@ -1642,7 +1644,9 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { "spring.data.mongodb.field-naming-strategy=org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy\n" + "#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 @@ -1653,7 +1657,9 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { "spring.data.mongodb.field-naming-strategy=java.lang.String\n" + "#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 editor = newEditor( @@ -1661,7 +1667,9 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { "spring.data.mongodb.field-naming-strategy=org.springframework.core.io.Resource\n" + "#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( "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( "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 { @@ -1851,8 +1859,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { editor = newEditor( "my.screen.background=green" ); - definitionLinkAsserts.assertLinkTargets(editor, "background", project, method("com.example.demo.MyProperties$Screen", "getScreen")); - definitionLinkAsserts.assertLinkTargets(editor, "green", project, field("com.example.demo.Color", "GREEN")); + 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, editor.rangeOf("green", "green"), field("com.example.demo.Color", "GREEN")); } @Test public void testNoHoverForUnrecognizedProperty() throws Exception { diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java index bc639058c..e1aa9bbe8 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java @@ -26,7 +26,6 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; 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.Configuration; import org.springframework.context.annotation.Import; @@ -631,8 +630,8 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { " getter-only: getme\n" ); - definitionLinkAsserts.assertLinkTargets(editor, "data", project, method("demo.FooProperties", "setData", "demo.ColorData")); - definitionLinkAsserts.assertLinkTargets(editor, "wavelen", project, method("demo.ColorData", "setWavelen", "double")); + definitionLinkAsserts.assertLinkTargets(editor, "data", project, editor.rangeOf("data:", "data"), method("demo.FooProperties", "setData", "demo.ColorData")); + definitionLinkAsserts.assertLinkTargets(editor, "wavelen", project, editor.rangeOf("wavelen:", "wavelen"), method("demo.ColorData", "setWavelen", "double")); } @Test @@ -653,11 +652,11 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { //io.spring.initializr.metadata.DefaultMetadataElement.setDefault(boolean) //io.spring.initializr.metadata.MetadataElement.setId(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, "id", project, 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, "name", project, editor.rangeOf("name:", "name"), method("io.spring.initializr.metadata.MetadataElement", "setName", "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, 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 { @@ -675,14 +674,17 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { ); definitionLinkAsserts.assertLinkTargets(editor, "port", p, + editor.rangeOf("port", "port"), method("org.springframework.boot.autoconfigure.web.ServerProperties", "setPort", "java.lang.Integer") ); 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", "tomcatDataSource"), method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "dbcpDataSource") ); definitionLinkAsserts.assertLinkTargets(editor, "init-sql", p, + editor.rangeOf("init-sqls", "init-sqls"), method("org.springframework.boot.autoconfigure.flyway.FlywayProperties", "setInitSqls", "java.util.List")); } @@ -3858,7 +3860,9 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { " mongodb:\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( "spring:\n" + @@ -3867,7 +3871,9 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { " field-naming-strategy:\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 editor = newEditor( @@ -3877,7 +3883,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { " field-naming-strategy: java.lang.String\n" + "#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 { @@ -4022,13 +4028,13 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { "my:\n" + " 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( "my:\n" + " 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 { @@ -4044,8 +4050,8 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { " RED: Rood\n" + " green: Groen\n" ); - definitionLinkAsserts.assertLinkTargets(editor, "RED", project, field("demo.Color", "RED")); - definitionLinkAsserts.assertLinkTargets(editor, "green", project, field("demo.Color", "GREEN")); + definitionLinkAsserts.assertLinkTargets(editor, "RED", project, editor.rangeOf("RED", "RED"), field("demo.Color", "RED")); + definitionLinkAsserts.assertLinkTargets(editor, "green", project, editor.rangeOf("green", "green"), field("demo.Color", "GREEN")); editor = newEditor( "spring:\n" + @@ -4054,6 +4060,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { " INDENT_OUTPUT: true" ); definitionLinkAsserts.assertLinkTargets(editor, "INDENT_OUTPUT", project, + editor.rangeOf("INDENT_OUTPUT", "INDENT_OUTPUT"), field("com.fasterxml.jackson.databind.SerializationFeature", "INDENT_OUTPUT") ); @@ -4064,6 +4071,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { " indent-output: true" ); definitionLinkAsserts.assertLinkTargets(editor, "indent-output", project, + editor.rangeOf("indent-output", "indent-output"), field("com.fasterxml.jackson.databind.SerializationFeature", "INDENT_OUTPUT") ); } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/DefinitionLinkAsserts.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/DefinitionLinkAsserts.java index bdc0a1edf..5d7ac5a97 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/DefinitionLinkAsserts.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/DefinitionLinkAsserts.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -27,6 +27,7 @@ import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.LocationLink; import org.eclipse.lsp4j.Range; import org.springframework.ide.vscode.boot.java.links.JavaDocumentUriProvider; 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 { - Set expectedLocations = Arrays.stream(methods).map(method -> { + public void assertLinkTargets(Editor editor, String hoverOver, IJavaProject project, Range highlightRange, JavaMethod... methods) throws Exception { + Set expectedLocations = Arrays.stream(methods).map(method -> { try { return getLocation(project, method); } catch (Exception 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); } - 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(expectedLocation)); + editor.assertLinkTargets(hoverOver, ImmutableSet.of(link)); } - 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 {