This is an automated email from the ASF dual-hosted git repository. dbalek pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push: new aadbec9 LSP: Go to Type Definition added. (#2939) aadbec9 is described below commit aadbec9ceb27459767a785845aa82677e4a372ca Author: Dusan Balek <dusan.ba...@oracle.com> AuthorDate: Fri May 7 15:00:25 2021 +0200 LSP: Go to Type Definition added. (#2939) --- ide/api.lsp/apichanges.xml | 96 ++++++++++++++++++++++ ide/api.lsp/manifest.mf | 2 +- ide/api.lsp/nbproject/project.properties | 1 + .../org/netbeans/api/lsp/HyperlinkLocation.java | 28 +++++++ .../spi/lsp/HyperlinkTypeDefLocationProvider.java | 56 +++++++++++++ java/java.editor/nbproject/project.xml | 2 +- .../netbeans/modules/editor/java/GoToSupport.java | 4 +- .../editor/hyperlink/JavaHyperlinkProvider.java | 12 ++- java/java.lsp.server/nbproject/project.xml | 2 +- .../modules/java/lsp/server/protocol/Server.java | 1 + .../server/protocol/TextDocumentServiceImpl.java | 26 +++++- .../java/lsp/server/protocol/ServerTest.java | 69 ++++++++++++++++ 12 files changed, 292 insertions(+), 7 deletions(-) diff --git a/ide/api.lsp/apichanges.xml b/ide/api.lsp/apichanges.xml new file mode 100644 index 0000000..e533835 --- /dev/null +++ b/ide/api.lsp/apichanges.xml @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> + +<?xml-stylesheet href="../../nbbuild/javadoctools/apichanges.xsl" type="text/xsl"?> +<!DOCTYPE apichanges PUBLIC "-//NetBeans//DTD API changes list 1.0//EN" "../../nbbuild/javadoctools/apichanges.dtd"> + +<!-- INFO FOR PEOPLE ADDING CHANGES: +[most of contents snipped - see openide's apichanges for how-to instructions] +<change> + <api name="compiler"/> + <summary>Some brief description here, can use <b>XHTML</b></summary> + <version major="1" minor="99"/> + <date day="13" month="6" year="2001"/> + <author login="jrhacker"/> + <compatibility addition="yes"/> + <description> + The main description of the change here. + Again can use full <b>XHTML</b> as needed. + </description> + <class package="org.openide.compiler" name="DoWhatIWantCompiler"/> + <issue number="14309"/> +</change> +--> + +<apichanges> + +<!-- First, a list of API names you may use: --> +<apidefs> + <apidef name="LSP_API">LSP APIs</apidef> +</apidefs> + +<!-- ACTUAL CHANGES BEGIN HERE: --> + +<changes> + <change id="HyperlinkTypeDefLocationProvider"> + <api name="LSP_API"/> + <summary>Adding HyperlinkTypeDefLocationProvider</summary> + <version major="1" minor="1"/> + <date day="5" month="5" year="2021"/> + <author login="dbalek"/> + <compatibility binary="compatible" source="compatible" addition="yes" deletion="no"/> + <description> + A <code>HyperlinkTypeDefLocationProvider</code> interface introduced that allows to + compute hyperlinks to type definition locations. + </description> + <class package="org.netbeans.spi.lsp" name="HyperlinkTypeDefLocationProvider"/> + </change> +</changes> + + <!-- Now the surrounding HTML text and document structure: --> + + <htmlcontents> +<!-- + NO NO NO NO NO! + ==============> DO NOT EDIT ME! <====================== + AUTOMATICALLY GENERATED FROM APICHANGES.XML, DO NOT EDIT + SEE xml/api/doc/changes/apichanges.xml +--> + <head> + <title>LSP API changes by date</title> + <link rel="stylesheet" href="prose.css" type="text/css"/> + </head> + <body> + +<p class="overviewlink"><a href="overview-summary.html">Overview</a></p> + +<h1>Introduction</h1> + +<p>This document lists changes made to the LSP APIs. Please ask on the + <code>d...@netbeans.apache.org</code> + mailing list if you have any questions about the details of a + change, or are wondering how to convert existing code to be compatible. +</p> + + <hr/><standard-changelists module-code-name="org.netbeans.api.lsp/1"/> + + <hr/><p>@FOOTER@</p> + + </body> + </htmlcontents> +</apichanges> diff --git a/ide/api.lsp/manifest.mf b/ide/api.lsp/manifest.mf index 2a6458d..087bc50 100644 --- a/ide/api.lsp/manifest.mf +++ b/ide/api.lsp/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.api.lsp/1 OpenIDE-Module-Localizing-Bundle: org/netbeans/api/lsp/Bundle.properties -OpenIDE-Module-Specification-Version: 1.0 +OpenIDE-Module-Specification-Version: 1.1 AutoUpdate-Show-In-Client: false diff --git a/ide/api.lsp/nbproject/project.properties b/ide/api.lsp/nbproject/project.properties index 0f73a11..445f2ff 100644 --- a/ide/api.lsp/nbproject/project.properties +++ b/ide/api.lsp/nbproject/project.properties @@ -17,3 +17,4 @@ is.autoload=true javac.source=1.8 javac.compilerargs=-Xlint -Xlint:-serial +javadoc.apichanges=${basedir}/apichanges.xml \ No newline at end of file diff --git a/ide/api.lsp/src/org/netbeans/api/lsp/HyperlinkLocation.java b/ide/api.lsp/src/org/netbeans/api/lsp/HyperlinkLocation.java index 1c449a5..4ded8d2 100644 --- a/ide/api.lsp/src/org/netbeans/api/lsp/HyperlinkLocation.java +++ b/ide/api.lsp/src/org/netbeans/api/lsp/HyperlinkLocation.java @@ -29,6 +29,7 @@ import org.netbeans.api.editor.mimelookup.MimePath; import org.netbeans.lib.editor.util.swing.DocumentUtilities; import org.netbeans.modules.lsp.HyperlinkLocationAccessor; import org.netbeans.spi.lsp.HyperlinkLocationProvider; +import org.netbeans.spi.lsp.HyperlinkTypeDefLocationProvider; import org.openide.filesystems.FileObject; /** @@ -157,4 +158,31 @@ public final class HyperlinkLocation { return locations; }); } + + /** + * Resolves a hyperlink at the given document offset and returns its target + * type definition location(s). + * + * @param doc document on which to operate. + * @param offset offset within document + * @return target type definition location(s) + * + * @since 1.1 + */ + @NonNull + public static CompletableFuture<List<HyperlinkLocation>> resolveTypeDefinition(@NonNull final Document doc, final int offset) { + MimePath mimePath = MimePath.parse(DocumentUtilities.getMimeType(doc)); + CompletableFuture<HyperlinkLocation>[] futures = MimeLookup.getLookup(mimePath).lookupAll(HyperlinkTypeDefLocationProvider.class).stream() + .map(provider -> provider.getHyperlinkTypeDefLocation(doc, offset)).toArray(CompletableFuture[]::new); + return CompletableFuture.allOf(futures).thenApply(value -> { + List<HyperlinkLocation> locations = new ArrayList<>(futures.length); + for (CompletableFuture<HyperlinkLocation> future : futures) { + HyperlinkLocation location = future.getNow(null); + if (location != null) { + locations.add(location); + } + } + return locations; + }); + } } diff --git a/ide/api.lsp/src/org/netbeans/spi/lsp/HyperlinkTypeDefLocationProvider.java b/ide/api.lsp/src/org/netbeans/spi/lsp/HyperlinkTypeDefLocationProvider.java new file mode 100644 index 0000000..86e8196 --- /dev/null +++ b/ide/api.lsp/src/org/netbeans/spi/lsp/HyperlinkTypeDefLocationProvider.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.spi.lsp; + +import org.netbeans.api.lsp.HyperlinkLocation; +import java.util.concurrent.CompletableFuture; +import javax.swing.text.Document; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.spi.editor.mimelookup.MimeLocation; + +/** + * Interface for resolving hyperlinks to type definition locations. Implementations of the interface + * should be registered in MimeLookup. + * <pre> + * + * {@code @MimeRegistration(mimeType = "text/foo", service = HyperlinkTypeDefLocationProvider.class) + * public class FooHyperlinkTypeDefLocationProvider implements HyperlinkTypeDefLocationProvider { + * ... + * } + * } + * </pre> + * + * @author Dusan Balek + * @since 1.1 + */ +@MimeLocation(subfolderName = "HyperlinkTypeDefLocationProviders") +public interface HyperlinkTypeDefLocationProvider { + + /** + * Resolves a hyperlink at the given document offset and returns its + * target type definition location. + * + * @param doc document on which to operate. + * @param offset offset within document + * @return target location + * + * @since 1.1 + */ + CompletableFuture<HyperlinkLocation> getHyperlinkTypeDefLocation(@NonNull Document doc, int offset); +} diff --git a/java/java.editor/nbproject/project.xml b/java/java.editor/nbproject/project.xml index eaa3a89..460fd94 100644 --- a/java/java.editor/nbproject/project.xml +++ b/java/java.editor/nbproject/project.xml @@ -58,7 +58,7 @@ <compile-dependency/> <run-dependency> <release-version>1</release-version> - <specification-version>1.0</specification-version> + <specification-version>1.1</specification-version> </run-dependency> </dependency> <dependency> diff --git a/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java b/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java index 287c926..4e081dd 100644 --- a/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java +++ b/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java @@ -166,7 +166,7 @@ public class GoToSupport { } } - public static CompletableFuture<HyperlinkLocation> getGoToLocation(final Document doc, final int offset) { + public static CompletableFuture<HyperlinkLocation> getGoToLocation(final Document doc, final int offset, final boolean goToSource) { try { final FileObject fo = getFileObject(doc); if (fo != null) { @@ -182,7 +182,7 @@ public class GoToSupport { return; } - Context resolved = resolveContext(controller, doc, offset, false, false); + Context resolved = resolveContext(controller, doc, offset, goToSource, false); if (resolved == null) { target[0] = new GoToTarget(-1, -1, null, null, null, null, null, false); diff --git a/java/java.editor/src/org/netbeans/modules/java/editor/hyperlink/JavaHyperlinkProvider.java b/java/java.editor/src/org/netbeans/modules/java/editor/hyperlink/JavaHyperlinkProvider.java index 74030ee..6fbb1ef 100644 --- a/java/java.editor/src/org/netbeans/modules/java/editor/hyperlink/JavaHyperlinkProvider.java +++ b/java/java.editor/src/org/netbeans/modules/java/editor/hyperlink/JavaHyperlinkProvider.java @@ -32,6 +32,7 @@ import org.netbeans.lib.editor.hyperlink.spi.HyperlinkType; import org.netbeans.modules.editor.java.GoToSupport; import org.netbeans.modules.java.editor.overridden.GoToImplementation; import org.netbeans.spi.lsp.HyperlinkLocationProvider; +import org.netbeans.spi.lsp.HyperlinkTypeDefLocationProvider; /** * Implementation of the hyperlink provider for java language. @@ -88,7 +89,16 @@ public final class JavaHyperlinkProvider implements HyperlinkProviderExt { @Override public CompletableFuture<HyperlinkLocation> getHyperlinkLocation(Document doc, int offset) { - return GoToSupport.getGoToLocation(doc, offset); + return GoToSupport.getGoToLocation(doc, offset, false); + } + } + + @MimeRegistration(mimeType = "text/x-java", service = HyperlinkTypeDefLocationProvider.class) + public static class TypeDefLocationProvider implements HyperlinkTypeDefLocationProvider { + + @Override + public CompletableFuture<HyperlinkLocation> getHyperlinkTypeDefLocation(Document doc, int offset) { + return GoToSupport.getGoToLocation(doc, offset, true); } } } diff --git a/java/java.lsp.server/nbproject/project.xml b/java/java.lsp.server/nbproject/project.xml index f1992a9..901e384 100644 --- a/java/java.lsp.server/nbproject/project.xml +++ b/java/java.lsp.server/nbproject/project.xml @@ -92,7 +92,7 @@ <compile-dependency/> <run-dependency> <release-version>1</release-version> - <specification-version>1.0</specification-version> + <specification-version>1.1</specification-version> </run-dependency> </dependency> <dependency> diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java index d539e83..bda32ff 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java @@ -603,6 +603,7 @@ public final class Server { capabilities.setCodeActionProvider(new CodeActionOptions(Arrays.asList(CodeActionKind.QuickFix, CodeActionKind.Source))); capabilities.setDocumentSymbolProvider(true); capabilities.setDefinitionProvider(true); + capabilities.setTypeDefinitionProvider(true); capabilities.setImplementationProvider(true); capabilities.setDocumentHighlightProvider(true); capabilities.setReferencesProvider(true); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java index b106aec..42ae0ad 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java @@ -126,6 +126,7 @@ import org.eclipse.lsp4j.SymbolInformation; import org.eclipse.lsp4j.TextDocumentContentChangeEvent; import org.eclipse.lsp4j.TextDocumentEdit; import org.eclipse.lsp4j.TextEdit; +import org.eclipse.lsp4j.TypeDefinitionParams; import org.eclipse.lsp4j.VersionedTextDocumentIdentifier; import org.eclipse.lsp4j.WorkspaceEdit; import org.eclipse.lsp4j.jsonrpc.messages.Either; @@ -526,6 +527,29 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli } @Override + public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> typeDefinition(TypeDefinitionParams params) { + try { + String uri = params.getTextDocument().getUri(); + Document doc = openedDocuments.get(uri); + if (doc != null) { + FileObject file = Utils.fromUri(uri); + if (file != null) { + int offset = Utils.getOffset(doc, params.getPosition()); + return HyperlinkLocation.resolveTypeDefinition(doc, offset).thenApply(locs -> { + return Either.forLeft(locs.stream().map(location -> { + FileObject fo = location.getFileObject(); + return new Location(Utils.toUri(fo), new Range(Utils.createPosition(fo, location.getStartOffset()), Utils.createPosition(fo, location.getEndOffset()))); + }).collect(Collectors.toList())); + }); + } + } + } catch (MalformedURLException ex) { + client.logMessage(new MessageParams(MessageType.Error, ex.getMessage())); + } + return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList())); + } + + @Override public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> implementation(ImplementationParams params) { // shortcut: if the projects are not yet initialized, return empty: if (server.openedProjects().getNow(null) == null) { @@ -682,7 +706,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli } } if (!sourceRoots.isEmpty()) { - query[0].getContext().add(org.netbeans.modules.refactoring.api.Scope.create(sourceRoots, null, null)); + query[0].getContext().add(org.netbeans.modules.refactoring.api.Scope.create(sourceRoots, null, null, true)); } cancelCallback[0] = () -> query[0].cancelRequest(); RefactoringSession refactoring = RefactoringSession.create("FindUsages"); diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java index f8f5e82..d3d6076 100644 --- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java +++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java @@ -109,6 +109,7 @@ import org.eclipse.lsp4j.TextDocumentEdit; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.eclipse.lsp4j.TextDocumentItem; import org.eclipse.lsp4j.TextEdit; +import org.eclipse.lsp4j.TypeDefinitionParams; import org.eclipse.lsp4j.VersionedTextDocumentIdentifier; import org.eclipse.lsp4j.WorkDoneProgressCancelParams; import org.eclipse.lsp4j.WorkDoneProgressCreateParams; @@ -882,6 +883,74 @@ public class ServerTest extends NbTestCase { assertEquals(20, definition.get(0).getRange().getEnd().getCharacter()); } + public void testGoToTypeDefinition() throws Exception { + File src = new File(getWorkDir(), "Test.java"); + src.getParentFile().mkdirs(); + try (Writer w = new FileWriter(new File(src.getParentFile(), ".test-project"))) {} + String code = "public class Test {\n" + + " private Other field;\n" + + " public void test() {\n" + + " System.err.println(field);\n" + + " }\n" + + "}\n"; + try (Writer w = new FileWriter(src)) { + w.write(code); + } + File otherSrc = new File(getWorkDir(), "Other.java"); + try (Writer w = new FileWriter(otherSrc)) { + w.write("/**Some source*/\n" + + "public class Other {\n" + + " public void test() { }\n" + + "}"); + } + FileUtil.refreshFor(getWorkDir()); + CountDownLatch indexingComplete = new CountDownLatch(1); + Launcher<LanguageServer> serverLauncher = LSPLauncher.createClientLauncher(new LspClient() { + @Override + public void telemetryEvent(Object arg0) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void publishDiagnostics(PublishDiagnosticsParams params) { + } + + @Override + public void showMessage(MessageParams params) { + if (Server.INDEXING_COMPLETED.equals(params.getMessage())) { + indexingComplete.countDown(); + } else { + throw new UnsupportedOperationException("Unexpected message."); + } + } + + @Override + public CompletableFuture<MessageActionItem> showMessageRequest(ShowMessageRequestParams arg0) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void logMessage(MessageParams arg0) { + throw new UnsupportedOperationException("Not supported yet."); + } + }, client.getInputStream(), client.getOutputStream()); + serverLauncher.startListening(); + LanguageServer server = serverLauncher.getRemoteProxy(); + InitializeParams initParams = new InitializeParams(); + initParams.setRootUri(getWorkDir().toURI().toString()); + server.initialize(initParams).get(); + indexingComplete.await(); + server.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(new TextDocumentItem(toURI(src), "java", 0, code))); + Position pos = new Position(3, 30); + List<? extends Location> typeDefinition = server.getTextDocumentService().typeDefinition(new TypeDefinitionParams(new TextDocumentIdentifier(toURI(src)), pos)).get().getLeft(); + assertEquals(1, typeDefinition.size()); + assertEquals(toURI(otherSrc), typeDefinition.get(0).getUri()); + assertEquals(1, typeDefinition.get(0).getRange().getStart().getLine()); + assertEquals(13, typeDefinition.get(0).getRange().getStart().getCharacter()); + assertEquals(1, typeDefinition.get(0).getRange().getEnd().getLine()); + assertEquals(18, typeDefinition.get(0).getRange().getEnd().getCharacter()); + } + public void testGoToImplementations() throws Exception { File src = new File(getWorkDir(), "Test.java"); src.getParentFile().mkdirs(); --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org For additional commands, e-mail: commits-h...@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists