From 40f66f6cb3ad46db573f1963d973e106502b0aa1 Mon Sep 17 00:00:00 2001 From: Shi Chen Date: Thu, 24 Mar 2022 10:46:57 +0800 Subject: [PATCH] Move TypeHierarchy to LSP Signed-off-by: Shi Chen --- org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF | 3 +- org.eclipse.jdt.ls.core/plugin.xml | 6 - .../internal/JDTDelegateCommandHandler.java | 29 --- .../core/internal/handlers/InitHandler.java | 1 + .../internal/handlers/JDTLanguageServer.java | 26 ++- .../TypeHierarchyHandler.java} | 210 ++++++++++-------- .../lsp/TextDocumentProtocolExtensions.java | 29 +++ .../lsp/TypeHierarchyProtocolExtensions.java | 34 +++ .../typeHierarchy/TypeHierarchyItem.java | 143 ++++++++++++ .../TypeHierarchyPrepareParams.java | 19 ++ .../TypeHierarchySubtypesParams.java | 30 +++ .../TypeHierarchySupertypesParams.java | 30 +++ .../commands/TypeHierarchyCommandTest.java | 117 ---------- .../handlers/TypeHierarchyHandlerTest.java | 73 ++++++ 14 files changed, 500 insertions(+), 250 deletions(-) rename org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/{commands/TypeHierarchyCommand.java => handlers/TypeHierarchyHandler.java} (53%) create mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/lsp/TextDocumentProtocolExtensions.java create mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/lsp/TypeHierarchyProtocolExtensions.java create mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchyItem.java create mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchyPrepareParams.java create mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchySubtypesParams.java create mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchySupertypesParams.java delete mode 100644 org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/commands/TypeHierarchyCommandTest.java create mode 100644 org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/TypeHierarchyHandlerTest.java diff --git a/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF index acd9441f7d..f3ceb07ff5 100644 --- a/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF @@ -56,7 +56,8 @@ Export-Package: org.eclipse.jdt.ls.core.internal;x-friends:="org.eclipse.jdt.ls. org.eclipse.jdt.ls.core.internal.text.correction;x-friends:="org.eclipse.jdt.ls.tests", org.eclipse.jdt.ls.internal.gradle.checksums;x-friends:="org.eclipse.jdt.ls.tests", org.eclipse.jdt.ls.core.internal.filesystem;x-friends:="org.eclipse.jdt.ls.tests", - org.eclipse.lsp4j.proposed;x-friends:="org.eclipse.jdt.ls.tests" + org.eclipse.lsp4j.proposed;x-friends:="org.eclipse.jdt.ls.tests", + org.eclipse.jdt.ls.core.internal.typeHierarchy;x-friends:="org.eclipse.jdt.ls.tests" Bundle-ClassPath: lib/jsoup-1.14.2.jar, lib/remark-1.2.0.jar, . diff --git a/org.eclipse.jdt.ls.core/plugin.xml b/org.eclipse.jdt.ls.core/plugin.xml index ad23424d3a..47204615c8 100644 --- a/org.eclipse.jdt.ls.core/plugin.xml +++ b/org.eclipse.jdt.ls.core/plugin.xml @@ -94,12 +94,6 @@ - - - - diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTDelegateCommandHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTDelegateCommandHandler.java index dada4454b2..0d87340d11 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTDelegateCommandHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTDelegateCommandHandler.java @@ -24,16 +24,10 @@ import org.eclipse.jdt.ls.core.internal.commands.ProjectCommand; import org.eclipse.jdt.ls.core.internal.commands.ProjectCommand.ClasspathOptions; import org.eclipse.jdt.ls.core.internal.commands.SourceAttachmentCommand; -import org.eclipse.jdt.ls.core.internal.commands.TypeHierarchyCommand; import org.eclipse.jdt.ls.core.internal.handlers.FormatterHandler; import org.eclipse.jdt.ls.core.internal.handlers.ResolveSourceMappingHandler; import org.eclipse.jdt.ls.core.internal.managers.GradleProjectImporter; -import org.eclipse.lsp4j.ResolveTypeHierarchyItemParams; import org.eclipse.lsp4j.SymbolInformation; -import org.eclipse.lsp4j.TextDocumentPositionParams; -import org.eclipse.lsp4j.TypeHierarchyDirection; -import org.eclipse.lsp4j.TypeHierarchyItem; -import org.eclipse.lsp4j.TypeHierarchyParams; import org.eclipse.lsp4j.WorkspaceEdit; public class JDTDelegateCommandHandler implements IDelegateCommandHandler { @@ -93,29 +87,6 @@ public Object executeCommand(String commandId, List arguments, IProgress projectNames = (ArrayList) arguments.get(1); } return ResolveSourceMappingHandler.resolveStackTraceLocation((String) arguments.get(0), projectNames); - case "java.navigate.resolveTypeHierarchy": - TypeHierarchyCommand resolveTypeHierarchyCommand = new TypeHierarchyCommand(); - TypeHierarchyItem toResolve = JSONUtility.toModel(arguments.get(0), TypeHierarchyItem.class); - TypeHierarchyDirection resolveDirection = TypeHierarchyDirection.forValue(JSONUtility.toModel(arguments.get(1), Integer.class)); - int resolveDepth = JSONUtility.toModel(arguments.get(2), Integer.class); - ResolveTypeHierarchyItemParams resolveParams = new ResolveTypeHierarchyItemParams(); - resolveParams.setItem(toResolve); - resolveParams.setDirection(resolveDirection); - resolveParams.setResolve(resolveDepth); - TypeHierarchyItem resolvedItem = resolveTypeHierarchyCommand.resolveTypeHierarchy(resolveParams, monitor); - return resolvedItem; - case "java.navigate.openTypeHierarchy": - TypeHierarchyCommand typeHierarchyCommand = new TypeHierarchyCommand(); - TypeHierarchyParams params = new TypeHierarchyParams(); - TextDocumentPositionParams textParams = JSONUtility.toModel(arguments.get(0), TextDocumentPositionParams.class); - TypeHierarchyDirection direction = TypeHierarchyDirection.forValue(JSONUtility.toModel(arguments.get(1), Integer.class)); - int resolve = JSONUtility.toModel(arguments.get(2), Integer.class); - params.setResolve(resolve); - params.setDirection(direction); - params.setTextDocument(textParams.getTextDocument()); - params.setPosition(textParams.getPosition()); - TypeHierarchyItem typeHierarchyItem = typeHierarchyCommand.typeHierarchy(params, monitor); - return typeHierarchyItem; case "java.project.upgradeGradle": String projectUri = (String) arguments.get(0); return GradleProjectImporter.upgradeGradleVersion(projectUri, monitor); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/InitHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/InitHandler.java index f1f78cc0bc..712f19d268 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/InitHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/InitHandler.java @@ -202,6 +202,7 @@ public void registerCapabilities(InitializeResult initializeResult) { )); semanticTokensOptions.setLegend(SemanticTokensHandler.legend()); capabilities.setSemanticTokensProvider(semanticTokensOptions); + capabilities.setTypeHierarchyProvider(Boolean.TRUE); initializeResult.setCapabilities(capabilities); } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java index 1ff328c461..4c05836c24 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java @@ -68,10 +68,16 @@ import org.eclipse.jdt.ls.core.internal.handlers.OverrideMethodsHandler.OverridableMethodsResponse; import org.eclipse.jdt.ls.core.internal.handlers.WorkspaceSymbolHandler.SearchSymbolParams; import org.eclipse.jdt.ls.core.internal.lsp.JavaProtocolExtensions; +import org.eclipse.jdt.ls.core.internal.lsp.TextDocumentProtocolExtensions; +import org.eclipse.jdt.ls.core.internal.lsp.TypeHierarchyProtocolExtensions; import org.eclipse.jdt.ls.core.internal.managers.ContentProviderManager; import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager; import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager; import org.eclipse.jdt.ls.core.internal.preferences.Preferences; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchyItem; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchyPrepareParams; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchySubtypesParams; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchySupertypesParams; import org.eclipse.lsp4j.CallHierarchyIncomingCall; import org.eclipse.lsp4j.CallHierarchyIncomingCallsParams; import org.eclipse.lsp4j.CallHierarchyItem; @@ -151,7 +157,7 @@ * */ public class JDTLanguageServer extends BaseJDTLanguageServer implements LanguageServer, TextDocumentService, WorkspaceService, - JavaProtocolExtensions, InlayHintProvider { + JavaProtocolExtensions, InlayHintProvider, TextDocumentProtocolExtensions, TypeHierarchyProtocolExtensions { public static final String JAVA_LSP_JOIN_ON_COMPLETION = "java.lsp.joinOnCompletion"; public static final String JAVA_LSP_INITIALIZE_WORKSPACE = "java.lsp.initializeWorkspace"; @@ -167,6 +173,7 @@ public class JDTLanguageServer extends BaseJDTLanguageServer implements Language private ClasspathUpdateHandler classpathUpdateHandler; private JVMConfigurator jvmConfigurator; private WorkspaceExecuteCommandHandler commandHandler; + private TypeHierarchyHandler typeHierarchyHandler = new TypeHierarchyHandler(); private ProgressReporterManager progressReporterManager; /** @@ -1034,6 +1041,23 @@ public CompletableFuture> inlayHint(InlayHintParams params) { return computeAsync(monitor -> new InlayHintsHandler(preferenceManager).inlayHint(params, monitor)); } + public CompletableFuture> prepareTypeHierarchy(TypeHierarchyPrepareParams params) { + logInfo(">> textDocument/prepareTypeHierarchy"); + return computeAsync(monitor -> typeHierarchyHandler.prepareTypeHierarchy(params, monitor)); + } + + @Override + public CompletableFuture> supertypes(TypeHierarchySupertypesParams params) { + logInfo(">> typeHierarchy/supertypes"); + return computeAsync(monitor -> typeHierarchyHandler.getSupertypeItems(params, monitor)); + } + + @Override + public CompletableFuture> subtypes(TypeHierarchySubtypesParams params) { + logInfo(">> typeHierarchy/subtypes"); + return computeAsync(monitor -> typeHierarchyHandler.getSubtypeItems(params, monitor)); + } + private CompletableFuture computeAsyncWithClientProgress(Function code) { return CompletableFutures.computeAsync((cc) -> { IProgressMonitor monitor = progressReporterManager.getProgressReporter(cc); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/commands/TypeHierarchyCommand.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/TypeHierarchyHandler.java similarity index 53% rename from org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/commands/TypeHierarchyCommand.java rename to org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/TypeHierarchyHandler.java index 16434ba867..81c086422f 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/commands/TypeHierarchyCommand.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/TypeHierarchyHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2021 Microsoft Corporation and others. + * Copyright (c) 2022 Microsoft Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -10,9 +10,11 @@ * Contributors: * Microsoft Corporation - initial API and implementation *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.commands; +package org.eclipse.jdt.ls.core.internal.handlers; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; @@ -28,86 +30,53 @@ import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner; import org.eclipse.jdt.ls.core.internal.JDTUtils; -import org.eclipse.jdt.ls.core.internal.JSONUtility; import org.eclipse.jdt.ls.core.internal.JDTUtils.LocationType; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchyItem; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchyPrepareParams; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchySubtypesParams; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchySupertypesParams; +import org.eclipse.jdt.ls.core.internal.JSONUtility; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; -import org.eclipse.jdt.ls.core.internal.handlers.DocumentSymbolHandler; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.Range; -import org.eclipse.lsp4j.ResolveTypeHierarchyItemParams; +import org.eclipse.lsp4j.SymbolTag; import org.eclipse.lsp4j.TextDocumentIdentifier; -import org.eclipse.lsp4j.TypeHierarchyDirection; -import org.eclipse.lsp4j.TypeHierarchyItem; -import org.eclipse.lsp4j.TypeHierarchyParams; -public class TypeHierarchyCommand { +public class TypeHierarchyHandler { - public TypeHierarchyItem typeHierarchy(TypeHierarchyParams params, IProgressMonitor monitor) { + public List prepareTypeHierarchy(TypeHierarchyPrepareParams params, IProgressMonitor monitor) { if (params == null) { - return null; + return Collections.emptyList(); } TextDocumentIdentifier textDocument = params.getTextDocument(); if (textDocument == null) { - return null; + return Collections.emptyList(); } Position position = params.getPosition(); String uri = textDocument.getUri(); - TypeHierarchyDirection direction = params.getDirection(); - int resolve = params.getResolve(); - return getTypeHierarchy(uri, position, direction, resolve, null, monitor); - } - - public TypeHierarchyItem resolveTypeHierarchy(ResolveTypeHierarchyItemParams params, IProgressMonitor monitor) { - if (params == null) { - return null; - } - TypeHierarchyItem item = params.getItem(); - if (item == null) { - return null; - } - Range range = item.getRange(); - if (range == null) { - return null; - } - Position position = range.getStart(); - String uri = item.getUri(); - TypeHierarchyDirection direction = params.getDirection(); - int resolve = params.getResolve(); - return getTypeHierarchy(uri, position, direction, resolve, item, monitor); + return getTypeHierarchyItems(uri, position, null, monitor); } - private TypeHierarchyItem getTypeHierarchy(String uri, Position position, TypeHierarchyDirection direction, int resolve, TypeHierarchyItem itemInput, IProgressMonitor monitor) { - if (uri == null || position == null || direction == null) { - return null; + private List getTypeHierarchyItems(String uri, Position position, TypeHierarchyItem itemInput, IProgressMonitor monitor) { + if (uri == null || position == null) { + return Collections.emptyList(); } try { IType type = null; if (itemInput == null) { type = getType(uri, position, monitor); - } else { - String handleIdentifier = JSONUtility.toModel(itemInput.getData(), String.class); - IJavaElement element = JavaCore.create(handleIdentifier); - if (element instanceof IType) { - type = ((IType)element); - } else if (element instanceof IOrdinaryClassFile) { - type = ((IOrdinaryClassFile)element).getType(); - } else { - return null; - } } - TypeHierarchyItem item = TypeHierarchyCommand.toTypeHierarchyItem(type); + TypeHierarchyItem item = TypeHierarchyHandler.toTypeHierarchyItem(type); if (item == null) { - return null; + return Collections.emptyList(); } - resolve(item, type, direction, resolve, monitor); - return item; + return Arrays.asList(item); } catch (JavaModelException e) { - return null; + return Collections.emptyList(); } } - private IType getType(String uri, Position position, IProgressMonitor monitor) throws JavaModelException { + public static IType getType(String uri, Position position, IProgressMonitor monitor) throws JavaModelException { IJavaElement typeElement = findTypeElement(JDTUtils.resolveTypeRoot(uri), position, monitor); if (typeElement instanceof IType) { return (IType)typeElement; @@ -133,6 +102,93 @@ private static IJavaElement findTypeElement(ITypeRoot unit, Position position, I return element; } + private static Location getLocation(IType type, LocationType locationType) throws JavaModelException { + Location location = locationType.toLocation(type); + if (location == null && type.getClassFile() != null) { + location = JDTUtils.toLocation(type.getClassFile()); + } + return location; + } + + public List getSupertypeItems(TypeHierarchySupertypesParams params, IProgressMonitor monitor) { + TypeHierarchyItem item = params.getItem(); + IType type = getTypeForItem(item); + if (type == null) { + return Collections.emptyList(); + } + return resolveSupertypes(type, monitor); + } + + private IType getTypeForItem(TypeHierarchyItem item) { + Object data = item.getData(); + if (data == null) { + return null; + } + String handleIdentifier = JSONUtility.toModel(data, String.class); + IType type = null; + IJavaElement element = JavaCore.create(handleIdentifier); + if (element instanceof IType) { + type = ((IType)element); + } else if (element instanceof IOrdinaryClassFile) { + type = ((IOrdinaryClassFile)element).getType(); + } else { + return null; + } + return type; + } + + private List resolveSupertypes(IType type, IProgressMonitor monitor) { + if (monitor.isCanceled()) { + return Collections.emptyList(); + } + try { + ITypeHierarchy typeHierarchy = type.newSupertypeHierarchy(DefaultWorkingCopyOwner.PRIMARY, monitor); + List superItems = new ArrayList<>(); + IType[] superITypes = typeHierarchy.getSupertypes(type); + for (IType superIType : superITypes) { + TypeHierarchyItem superItem = TypeHierarchyHandler.toTypeHierarchyItem(superIType); + if (superItem == null) { + continue; + } + superItems.add(superItem); + } + return superItems; + } catch (JavaModelException e) { + return Collections.emptyList(); + } + } + + public List getSubtypeItems(TypeHierarchySubtypesParams params, IProgressMonitor monitor) { + TypeHierarchyItem item = params.getItem(); + IType type = getTypeForItem(item); + // for Object we will not show its subtypes + if (type == null || type.getFullyQualifiedName().equals("java.lang.Object")) { + return Collections.emptyList(); + } + return resolveSubtypes(type, monitor); + } + + private List resolveSubtypes(IType type, IProgressMonitor monitor) { + if (monitor.isCanceled()) { + return Collections.emptyList(); + } + try { + ITypeHierarchy typeHierarchy = type.newTypeHierarchy(type.getJavaProject(), DefaultWorkingCopyOwner.PRIMARY, monitor); + List subItems = new ArrayList<>(); + IType[] subITypes = typeHierarchy.getSubtypes(type); + for (IType subIType : subITypes) { + TypeHierarchyItem subItem = TypeHierarchyHandler.toTypeHierarchyItem(subIType); + if (subItem == null) { + continue; + } + subItems.add(subItem); + } + return subItems; + } catch (JavaModelException e) { + return Collections.emptyList(); + } + } + private static TypeHierarchyItem toTypeHierarchyItem(IType type) throws JavaModelException { if (type == null) { return null; @@ -159,49 +215,11 @@ private static TypeHierarchyItem toTypeHierarchyItem(IType type) throws JavaMode } } item.setKind(DocumentSymbolHandler.mapKind(type)); - item.setDeprecated(JDTUtils.isDeprecated(type)); + if (JDTUtils.isDeprecated(type)) { + List tags = Arrays.asList(SymbolTag.Deprecated); + item.setTags(tags); + } item.setData(type.getHandleIdentifier()); return item; } - - private static Location getLocation(IType type, LocationType locationType) throws JavaModelException { - Location location = locationType.toLocation(type); - if (location == null && type.getClassFile() != null) { - location = JDTUtils.toLocation(type.getClassFile()); - } - return location; - } - - private void resolve(TypeHierarchyItem item, IType type, TypeHierarchyDirection direction, int resolve, IProgressMonitor monitor) throws JavaModelException { - if (monitor.isCanceled() || resolve <= 0) { - return; - } - ITypeHierarchy typeHierarchy = (direction == TypeHierarchyDirection.Parents) ? type.newSupertypeHierarchy(DefaultWorkingCopyOwner.PRIMARY, monitor) : type.newTypeHierarchy(type.getJavaProject(), DefaultWorkingCopyOwner.PRIMARY, monitor); - if (direction == TypeHierarchyDirection.Children || direction == TypeHierarchyDirection.Both) { - List childrenItems = new ArrayList(); - IType[] children = typeHierarchy.getSubtypes(type); - for (IType childType : children) { - TypeHierarchyItem childItem = TypeHierarchyCommand.toTypeHierarchyItem(childType); - if (childItem == null) { - continue; - } - resolve(childItem, childType, direction, resolve - 1, monitor); - childrenItems.add(childItem); - } - item.setChildren(childrenItems); - } - if (direction == TypeHierarchyDirection.Parents || direction == TypeHierarchyDirection.Both) { - List parentsItems = new ArrayList(); - IType[] parents = typeHierarchy.getSupertypes(type); - for (IType parentType : parents) { - TypeHierarchyItem parentItem = TypeHierarchyCommand.toTypeHierarchyItem(parentType); - if (parentItem == null) { - continue; - } - resolve(parentItem, parentType, direction, resolve - 1, monitor); - parentsItems.add(parentItem); - } - item.setParents(parentsItems); - } - } } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/lsp/TextDocumentProtocolExtensions.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/lsp/TextDocumentProtocolExtensions.java new file mode 100644 index 0000000000..f076221939 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/lsp/TextDocumentProtocolExtensions.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2022 Microsoft Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation +*******************************************************************************/ + +package org.eclipse.jdt.ls.core.internal.lsp; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchyItem; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchyPrepareParams; +import org.eclipse.lsp4j.jsonrpc.services.JsonRequest; +import org.eclipse.lsp4j.jsonrpc.services.JsonSegment; + +@JsonSegment("textDocument") +public interface TextDocumentProtocolExtensions { + + @JsonRequest + CompletableFuture> prepareTypeHierarchy(TypeHierarchyPrepareParams params); +} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/lsp/TypeHierarchyProtocolExtensions.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/lsp/TypeHierarchyProtocolExtensions.java new file mode 100644 index 0000000000..13eee3a5ae --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/lsp/TypeHierarchyProtocolExtensions.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2022 Microsoft Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation +*******************************************************************************/ + +package org.eclipse.jdt.ls.core.internal.lsp; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchyItem; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchySubtypesParams; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchySupertypesParams; +import org.eclipse.lsp4j.jsonrpc.services.JsonRequest; +import org.eclipse.lsp4j.jsonrpc.services.JsonSegment; + +@JsonSegment("typeHierarchy") +public interface TypeHierarchyProtocolExtensions { + + @JsonRequest + CompletableFuture> supertypes(TypeHierarchySupertypesParams params); + + @JsonRequest + CompletableFuture> subtypes(TypeHierarchySubtypesParams params); + +} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchyItem.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchyItem.java new file mode 100644 index 0000000000..bb4bb3e728 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchyItem.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2022 Microsoft Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation +*******************************************************************************/ +package org.eclipse.jdt.ls.core.internal.typeHierarchy; + +import java.util.List; + +import com.google.gson.annotations.JsonAdapter; + +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.SymbolKind; +import org.eclipse.lsp4j.SymbolTag; +import org.eclipse.lsp4j.jsonrpc.json.adapters.JsonElementTypeAdapter; +import org.eclipse.lsp4j.jsonrpc.validation.NonNull; + +public class TypeHierarchyItem { + /** + * The name of this item. + */ + @NonNull + private String name; + + /** + * The kind of this item. + */ + @NonNull + private SymbolKind kind; + + /** + * Tags for this item. + */ + private List tags; + + /** + * More detail for this item, e.g. the signature of a function. + */ + private String detail; + + /** + * The resource identifier of this item. + */ + @NonNull + private String uri; + + /** + * The range enclosing this symbol not including leading/trailing whitespace + * but everything else, e.g. comments and code. + */ + @NonNull + private Range range; + + /** + * The range that should be selected and revealed when this type hierarchy item + * is being picked, e.g the name of a function. Must be contained by the the + * {@link TypeHierarchyItem#getRange range}. + * + * @see TypeHierarchyItem#range + */ + @NonNull + private Range selectionRange; + + /** + * A data entry field that is preserved between a type hierarchy prepare and + * supertypes or subtypes requests. It could also be used to identify the + * type hierarchy in the server, helping improve the performance on + * resolving supertypes and subtypes. + */ + @JsonAdapter(JsonElementTypeAdapter.Factory.class) + private Object data; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public SymbolKind getKind() { + return kind; + } + + public void setKind(SymbolKind kind) { + this.kind = kind; + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public Range getRange() { + return range; + } + + public void setRange(Range range) { + this.range = range; + } + + public Range getSelectionRange() { + return selectionRange; + } + + public void setSelectionRange(Range selectionRange) { + this.selectionRange = selectionRange; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchyPrepareParams.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchyPrepareParams.java new file mode 100644 index 0000000000..05dddefa92 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchyPrepareParams.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2022 Microsoft Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation +*******************************************************************************/ +package org.eclipse.jdt.ls.core.internal.typeHierarchy; + +import org.eclipse.lsp4j.TextDocumentPositionAndWorkDoneProgressParams; + +public class TypeHierarchyPrepareParams extends TextDocumentPositionAndWorkDoneProgressParams { + +} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchySubtypesParams.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchySubtypesParams.java new file mode 100644 index 0000000000..d15cc2b422 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchySubtypesParams.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2022 Microsoft Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation +*******************************************************************************/ +package org.eclipse.jdt.ls.core.internal.typeHierarchy; + +import org.eclipse.lsp4j.TextDocumentPositionAndWorkDoneProgressParams; +import org.eclipse.lsp4j.jsonrpc.validation.NonNull; + +public class TypeHierarchySubtypesParams extends TextDocumentPositionAndWorkDoneProgressParams{ + + @NonNull + private TypeHierarchyItem item; + + public TypeHierarchyItem getItem() { + return item; + } + + public void setItem(TypeHierarchyItem item) { + this.item = item; + } +} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchySupertypesParams.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchySupertypesParams.java new file mode 100644 index 0000000000..90652294a2 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/typeHierarchy/TypeHierarchySupertypesParams.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2022 Microsoft Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation +*******************************************************************************/ +package org.eclipse.jdt.ls.core.internal.typeHierarchy; + +import org.eclipse.lsp4j.TextDocumentPositionAndWorkDoneProgressParams; +import org.eclipse.lsp4j.jsonrpc.validation.NonNull; + +public class TypeHierarchySupertypesParams extends TextDocumentPositionAndWorkDoneProgressParams{ + + @NonNull + private TypeHierarchyItem item; + + public TypeHierarchyItem getItem() { + return item; + } + + public void setItem(TypeHierarchyItem item) { + this.item = item; + } +} diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/commands/TypeHierarchyCommandTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/commands/TypeHierarchyCommandTest.java deleted file mode 100644 index 6b3345e9fb..0000000000 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/commands/TypeHierarchyCommandTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2021 Microsoft Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Microsoft Corporation - initial API and implementation -*******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.commands; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import java.util.List; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.jdt.ls.core.internal.WorkspaceHelper; -import org.eclipse.jdt.ls.core.internal.managers.AbstractInvisibleProjectBasedTest; -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.TextDocumentIdentifier; -import org.eclipse.lsp4j.TypeHierarchyDirection; -import org.eclipse.lsp4j.TypeHierarchyItem; -import org.eclipse.lsp4j.TypeHierarchyParams; -import org.junit.Before; -import org.junit.Test; - -public class TypeHierarchyCommandTest extends AbstractInvisibleProjectBasedTest { - - private IProject fJProject; - private TypeHierarchyCommand fCommand; - - @Before - public void setup() throws Exception { - importProjects("maven/salut"); - fJProject = WorkspaceHelper.getProject("salut"); - fCommand = new TypeHierarchyCommand(); - } - - @Test - public void testTypeHierarchy() throws Exception { - IProgressMonitor monitor = new NullProgressMonitor(); - TypeHierarchyParams params = new TypeHierarchyParams(); - String uriString = fJProject.getFile("src/main/java/org/sample/TestJavadoc.java").getLocationURI().toString(); - TextDocumentIdentifier identifier = new TextDocumentIdentifier(uriString); - Position position = new Position(4, 20); - params.setTextDocument(identifier); - params.setResolve(1); - params.setDirection(TypeHierarchyDirection.Both); - params.setPosition(position); - TypeHierarchyItem item = fCommand.typeHierarchy(params, monitor); - assertNotNull(item); - assertEquals(item.getName(), "TestJavadoc"); - assertNotNull(item.getChildren()); - assertEquals(item.getChildren().size(), 0); - assertNotNull(item.getParents()); - assertEquals(item.getParents().size(), 1); - assertEquals(item.getParents().get(0).getName(), "Object"); - } - - @Test - public void testSuperTypeHierarchy() throws Exception { - IProgressMonitor monitor = new NullProgressMonitor(); - TypeHierarchyParams params = new TypeHierarchyParams(); - String uriString = fJProject.getFile("src/main/java/org/sample/CallHierarchy.java").getLocationURI().toString(); - TextDocumentIdentifier identifier = new TextDocumentIdentifier(uriString); - Position position = new Position(7, 27); - params.setTextDocument(identifier); - params.setResolve(1); - params.setDirection(TypeHierarchyDirection.Parents); - params.setPosition(position); - TypeHierarchyItem item = fCommand.typeHierarchy(params, monitor); - assertNotNull(item); - assertEquals(item.getName(), "CallHierarchy$FooBuilder"); - assertNull(item.getChildren()); - assertEquals(item.getParents().size(), 2); - TypeHierarchyItem builder = item.getParents().get(0); - assertNotNull(builder); - assertEquals(builder.getName(), "Builder"); - assertNull(builder.getParents()); - TypeHierarchyItem object = item.getParents().get(1); - assertNotNull(object); - assertEquals(object.getName(), "Object"); - assertNull(object.getParents()); - } - - @Test - public void testSubTypeHierarchy() throws Exception { - IProgressMonitor monitor = new NullProgressMonitor(); - TypeHierarchyParams params = new TypeHierarchyParams(); - String uriString = fJProject.getFile("src/main/java/org/sample/CallHierarchy.java").getLocationURI().toString(); - TextDocumentIdentifier identifier = new TextDocumentIdentifier(uriString); - Position position = new Position(2, 43); - params.setTextDocument(identifier); - params.setResolve(2); - params.setDirection(TypeHierarchyDirection.Children); - params.setPosition(position); - TypeHierarchyItem item = fCommand.typeHierarchy(params, monitor); - assertNotNull(item); - assertEquals(item.getName(), "Builder"); - assertNull(item.getParents()); - assertEquals(item.getChildren().size(), 9); - for (TypeHierarchyItem child : item.getChildren()) { - List subChild = child.getChildren(); - assertNotNull(subChild); - if (subChild.size() == 1) { - assertEquals(subChild.get(0).getName(), "ReflectionToStringBuilder"); - } - } - } -} diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/TypeHierarchyHandlerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/TypeHierarchyHandlerTest.java new file mode 100644 index 0000000000..fa56403df5 --- /dev/null +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/TypeHierarchyHandlerTest.java @@ -0,0 +1,73 @@ +package org.eclipse.jdt.ls.core.internal.handlers; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.List; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.ls.core.internal.WorkspaceHelper; +import org.eclipse.jdt.ls.core.internal.managers.AbstractInvisibleProjectBasedTest; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchyItem; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchyPrepareParams; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchySubtypesParams; +import org.eclipse.jdt.ls.core.internal.typeHierarchy.TypeHierarchySupertypesParams; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.TextDocumentIdentifier; +import org.junit.Before; +import org.junit.Test; + +public class TypeHierarchyHandlerTest extends AbstractInvisibleProjectBasedTest { + + private IProject fJProject; + private TypeHierarchyHandler handler; + + @Before + public void setup() throws Exception { + importProjects("maven/salut"); + fJProject = WorkspaceHelper.getProject("salut"); + handler = new TypeHierarchyHandler(); + } + + @Test + public void testSuperTypeHierarchy() throws Exception { + IProgressMonitor monitor = new NullProgressMonitor(); + TypeHierarchyPrepareParams params = new TypeHierarchyPrepareParams(); + String uriString = fJProject.getFile("src/main/java/org/sample/CallHierarchy.java").getLocationURI().toString(); + TextDocumentIdentifier identifier = new TextDocumentIdentifier(uriString); + Position position = new Position(7, 27); + params.setTextDocument(identifier); + params.setPosition(position); + List items = handler.prepareTypeHierarchy(params, monitor); + assertNotNull(items); + assertEquals(items.size(), 1); + assertEquals(items.get(0).getName(), "CallHierarchy$FooBuilder"); + TypeHierarchySupertypesParams superParams = new TypeHierarchySupertypesParams(); + superParams.setItem(items.get(0)); + List superItems = handler.getSupertypeItems(superParams, monitor); + assertNotNull(superItems); + assertEquals(superItems.size(), 2); + } + + @Test + public void testSubTypeHierarchy() throws Exception { + IProgressMonitor monitor = new NullProgressMonitor(); + TypeHierarchyPrepareParams params = new TypeHierarchyPrepareParams(); + String uriString = fJProject.getFile("src/main/java/org/sample/CallHierarchy.java").getLocationURI().toString(); + TextDocumentIdentifier identifier = new TextDocumentIdentifier(uriString); + Position position = new Position(2, 43); + params.setTextDocument(identifier); + params.setPosition(position); + List items = handler.prepareTypeHierarchy(params, monitor); + assertNotNull(items); + assertEquals(items.size(), 1); + assertEquals(items.get(0).getName(), "Builder"); + TypeHierarchySubtypesParams subParams = new TypeHierarchySubtypesParams(); + subParams.setItem(items.get(0)); + List subItems = handler.getSubtypeItems(subParams, monitor); + assertNotNull(subItems); + assertEquals(subItems.size(), 9); + } +}