From c4a23dec0c40a9074f42ff2b5dbe65baa3a09456 Mon Sep 17 00:00:00 2001 From: Shi Chen Date: Wed, 3 Feb 2021 10:59:39 +0800 Subject: [PATCH 01/10] Support Type Hierarchy Signed-off-by: Shi Chen --- org.eclipse.jdt.ls.core/plugin.xml | 6 + .../internal/JDTDelegateCommandHandler.java | 29 +++ .../commands/TypeHierarchyCommand.java | 184 ++++++++++++++++++ .../commands/TypeHierarchyCommandTest.java | 117 +++++++++++ 4 files changed, 336 insertions(+) create mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/commands/TypeHierarchyCommand.java create mode 100644 org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/commands/TypeHierarchyCommandTest.java diff --git a/org.eclipse.jdt.ls.core/plugin.xml b/org.eclipse.jdt.ls.core/plugin.xml index aa62acfc5f..6d8d061f71 100644 --- a/org.eclipse.jdt.ls.core/plugin.xml +++ b/org.eclipse.jdt.ls.core/plugin.xml @@ -97,6 +97,12 @@ + + + + arguments, IProgress projectNames = (ArrayList) arguments.get(1); } return ResolveSourceMappingHandler.resolveStackTraceLocation((String) arguments.get(0), projectNames); + case "java.action.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 resolveItem = resolveTypeHierarchyCommand.resolveTypeHierarchy(resolveParams, monitor); + return resolveItem; + case "java.action.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; default: break; } 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/commands/TypeHierarchyCommand.java new file mode 100644 index 0000000000..826d086f5b --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/commands/TypeHierarchyCommand.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * 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 java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IOrdinaryClassFile; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.ITypeHierarchy; +import org.eclipse.jdt.core.ITypeRoot; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.ls.core.internal.JDTUtils; +import org.eclipse.jdt.ls.core.internal.JDTUtils.LocationType; +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.TextDocumentIdentifier; +import org.eclipse.lsp4j.TypeHierarchyDirection; +import org.eclipse.lsp4j.TypeHierarchyItem; +import org.eclipse.lsp4j.TypeHierarchyParams; + +public class TypeHierarchyCommand { + + public TypeHierarchyItem typeHierarchy(TypeHierarchyParams params, IProgressMonitor monitor) { + if (params == null) { + return null; + } + TextDocumentIdentifier textDocument = params.getTextDocument(); + if (textDocument == null) { + return null; + } + Position position = params.getPosition(); + String uri = textDocument.getUri(); + TypeHierarchyDirection direction = params.getDirection(); + int resolve = params.getResolve(); + return getTypeHierarchy(uri, position, direction, resolve, 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, monitor); + } + + private TypeHierarchyItem getTypeHierarchy(String uri, Position position, TypeHierarchyDirection direction, int resolve, IProgressMonitor monitor) { + if (uri == null || position == null || direction == null) { + return null; + } + try { + IType type = getType(uri, position, monitor); + TypeHierarchyItem item = TypeHierarchyCommand.toTypeHierarchyItem(type); + if (item == null) { + return null; + } + resolve(item, type, direction, resolve, monitor); + return item; + } catch (JavaModelException e) { + return null; + } + } + + private 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; + } else if (typeElement instanceof IMethod) { + return ((IMethod)typeElement).getDeclaringType(); + } else { + return null; + } + } + + private static IJavaElement findTypeElement(ITypeRoot unit, Position position, IProgressMonitor monitor) throws JavaModelException { + if (unit == null) { + return null; + } + IJavaElement element = JDTUtils.findElementAtSelection(unit, position.getLine(), position.getCharacter(), JavaLanguageServerPlugin.getPreferencesManager(), monitor); + if (element == null) { + if (unit instanceof IOrdinaryClassFile) { + element = ((IOrdinaryClassFile) unit).getType(); + } else if (unit instanceof ICompilationUnit) { + element = unit.findPrimaryType(); + } + } + return element; + } + + private static TypeHierarchyItem toTypeHierarchyItem(IType type) throws JavaModelException { + if (type == null) { + return null; + } + Location location = getLocation(type, LocationType.FULL_RANGE); + Location selectLocation = getLocation(type, LocationType.NAME_RANGE); + if (location == null || selectLocation == null) { + return null; + } + TypeHierarchyItem item = new TypeHierarchyItem(); + item.setRange(location.getRange()); + item.setUri(location.getUri()); + item.setSelectionRange(selectLocation.getRange()); + item.setName(JDTUtils.getName(type)); + item.setKind(DocumentSymbolHandler.mapKind(type)); + IPackageFragment packageFragment = type.getPackageFragment(); + if (packageFragment != null) { + item.setDetail(packageFragment.getElementName()); + } + item.setDeprecated(JDTUtils.isDeprecated(type)); + 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(monitor) : type.newTypeHierarchy(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.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 new file mode 100644 index 0000000000..25e410efaf --- /dev/null +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/commands/TypeHierarchyCommandTest.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * 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(), "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"); + } + } + } +} From dfb60cc694e380f195b9d7054187566672e3d6e3 Mon Sep 17 00:00:00 2001 From: Shi Chen Date: Fri, 26 Feb 2021 14:02:26 +0800 Subject: [PATCH 02/10] rename commands Signed-off-by: Shi Chen --- org.eclipse.jdt.ls.core/plugin.xml | 4 ++-- .../jdt/ls/core/internal/JDTDelegateCommandHandler.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/org.eclipse.jdt.ls.core/plugin.xml b/org.eclipse.jdt.ls.core/plugin.xml index 6d8d061f71..ec551066dc 100644 --- a/org.eclipse.jdt.ls.core/plugin.xml +++ b/org.eclipse.jdt.ls.core/plugin.xml @@ -98,10 +98,10 @@ id="java.project.resolveStackTraceLocation"> + id="java.navigate.openTypeHierarchy"> + id="java.navigate.resolveTypeHierarchy"> 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 e35799cfb1..75cccf36b6 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 @@ -92,7 +92,7 @@ public Object executeCommand(String commandId, List arguments, IProgress projectNames = (ArrayList) arguments.get(1); } return ResolveSourceMappingHandler.resolveStackTraceLocation((String) arguments.get(0), projectNames); - case "java.action.resolveTypeHierarchy": + 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)); @@ -103,7 +103,7 @@ public Object executeCommand(String commandId, List arguments, IProgress resolveParams.setResolve(resolveDepth); TypeHierarchyItem resolveItem = resolveTypeHierarchyCommand.resolveTypeHierarchy(resolveParams, monitor); return resolveItem; - case "java.action.openTypeHierarchy": + case "java.navigate.openTypeHierarchy": TypeHierarchyCommand typeHierarchyCommand = new TypeHierarchyCommand(); TypeHierarchyParams params = new TypeHierarchyParams(); TextDocumentPositionParams textParams = JSONUtility.toModel(arguments.get(0), TextDocumentPositionParams.class); From dbaba4d68fbaef763ae3d2949ddf6c71b84b5ffc Mon Sep 17 00:00:00 2001 From: Shi Chen Date: Mon, 1 Mar 2021 10:02:41 +0800 Subject: [PATCH 03/10] refine naming Signed-off-by: Shi Chen --- .../jdt/ls/core/internal/JDTDelegateCommandHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 75cccf36b6..dc1bdfc5b3 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 @@ -101,8 +101,8 @@ public Object executeCommand(String commandId, List arguments, IProgress resolveParams.setItem(toResolve); resolveParams.setDirection(resolveDirection); resolveParams.setResolve(resolveDepth); - TypeHierarchyItem resolveItem = resolveTypeHierarchyCommand.resolveTypeHierarchy(resolveParams, monitor); - return resolveItem; + TypeHierarchyItem resolvedItem = resolveTypeHierarchyCommand.resolveTypeHierarchy(resolveParams, monitor); + return resolvedItem; case "java.navigate.openTypeHierarchy": TypeHierarchyCommand typeHierarchyCommand = new TypeHierarchyCommand(); TypeHierarchyParams params = new TypeHierarchyParams(); From fa4c7857ac2de18fbec4fde6fd1432829781200a Mon Sep 17 00:00:00 2001 From: Shi Chen Date: Tue, 2 Mar 2021 11:24:46 +0800 Subject: [PATCH 04/10] De-duplicate the results Signed-off-by: Shi Chen --- .../core/internal/commands/TypeHierarchyCommand.java | 10 ++++++++++ 1 file changed, 10 insertions(+) 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/commands/TypeHierarchyCommand.java index 826d086f5b..db0d0a21f6 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/commands/TypeHierarchyCommand.java @@ -13,7 +13,9 @@ package org.eclipse.jdt.ls.core.internal.commands; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.ICompilationUnit; @@ -157,7 +159,11 @@ private void resolve(TypeHierarchyItem item, IType type, TypeHierarchyDirection if (direction == TypeHierarchyDirection.Children || direction == TypeHierarchyDirection.Both) { List childrenItems = new ArrayList(); IType[] children = typeHierarchy.getSubtypes(type); + Set fullyQualifiedNameSet = new HashSet<>(); for (IType childType : children) { + if (!fullyQualifiedNameSet.add(childType.getFullyQualifiedName())) { + continue; + } TypeHierarchyItem childItem = TypeHierarchyCommand.toTypeHierarchyItem(childType); if (childItem == null) { continue; @@ -170,7 +176,11 @@ private void resolve(TypeHierarchyItem item, IType type, TypeHierarchyDirection if (direction == TypeHierarchyDirection.Parents || direction == TypeHierarchyDirection.Both) { List parentsItems = new ArrayList(); IType[] parents = typeHierarchy.getSupertypes(type); + Set fullyQualifiedNameSet = new HashSet<>(); for (IType parentType : parents) { + if (!fullyQualifiedNameSet.add(parentType.getFullyQualifiedName())) { + continue; + } TypeHierarchyItem parentItem = TypeHierarchyCommand.toTypeHierarchyItem(parentType); if (parentItem == null) { continue; From 918e7a6ec4fb0f58c1aef292caa822a19d7426c3 Mon Sep 17 00:00:00 2001 From: Shi Chen Date: Tue, 2 Mar 2021 13:16:45 +0800 Subject: [PATCH 05/10] Restrict scope to De-duplicate results Signed-off-by: Shi Chen --- .../core/internal/commands/TypeHierarchyCommand.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) 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/commands/TypeHierarchyCommand.java index db0d0a21f6..8975998aad 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/commands/TypeHierarchyCommand.java @@ -13,9 +13,7 @@ package org.eclipse.jdt.ls.core.internal.commands; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.ICompilationUnit; @@ -155,15 +153,11 @@ private void resolve(TypeHierarchyItem item, IType type, TypeHierarchyDirection if (monitor.isCanceled() || resolve <= 0) { return; } - ITypeHierarchy typeHierarchy = (direction == TypeHierarchyDirection.Parents) ? type.newSupertypeHierarchy(monitor) : type.newTypeHierarchy(monitor); + ITypeHierarchy typeHierarchy = (direction == TypeHierarchyDirection.Parents) ? type.newSupertypeHierarchy(monitor) : type.newTypeHierarchy(type.getJavaProject(), monitor); if (direction == TypeHierarchyDirection.Children || direction == TypeHierarchyDirection.Both) { List childrenItems = new ArrayList(); IType[] children = typeHierarchy.getSubtypes(type); - Set fullyQualifiedNameSet = new HashSet<>(); for (IType childType : children) { - if (!fullyQualifiedNameSet.add(childType.getFullyQualifiedName())) { - continue; - } TypeHierarchyItem childItem = TypeHierarchyCommand.toTypeHierarchyItem(childType); if (childItem == null) { continue; @@ -176,11 +170,7 @@ private void resolve(TypeHierarchyItem item, IType type, TypeHierarchyDirection if (direction == TypeHierarchyDirection.Parents || direction == TypeHierarchyDirection.Both) { List parentsItems = new ArrayList(); IType[] parents = typeHierarchy.getSupertypes(type); - Set fullyQualifiedNameSet = new HashSet<>(); for (IType parentType : parents) { - if (!fullyQualifiedNameSet.add(parentType.getFullyQualifiedName())) { - continue; - } TypeHierarchyItem parentItem = TypeHierarchyCommand.toTypeHierarchyItem(parentType); if (parentItem == null) { continue; From 6d4161653951a3e6bd031459ee2fbc3b9b0d6370 Mon Sep 17 00:00:00 2001 From: Shi Chen Date: Tue, 2 Mar 2021 13:40:34 +0800 Subject: [PATCH 06/10] Use workingCopy to avoid inconsistent Signed-off-by: Shi Chen --- .../jdt/ls/core/internal/commands/TypeHierarchyCommand.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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/commands/TypeHierarchyCommand.java index 8975998aad..7fe2fba2d5 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/commands/TypeHierarchyCommand.java @@ -25,6 +25,7 @@ import org.eclipse.jdt.core.ITypeHierarchy; import org.eclipse.jdt.core.ITypeRoot; 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.JDTUtils.LocationType; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; @@ -153,7 +154,7 @@ private void resolve(TypeHierarchyItem item, IType type, TypeHierarchyDirection if (monitor.isCanceled() || resolve <= 0) { return; } - ITypeHierarchy typeHierarchy = (direction == TypeHierarchyDirection.Parents) ? type.newSupertypeHierarchy(monitor) : type.newTypeHierarchy(type.getJavaProject(), monitor); + 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); From 9bdcdaeb5075696ef3973d356de54389e96cedf2 Mon Sep 17 00:00:00 2001 From: Shi Chen Date: Tue, 2 Mar 2021 16:19:42 +0800 Subject: [PATCH 07/10] Optimize the display name of inner class Signed-off-by: Shi Chen --- .../internal/commands/TypeHierarchyCommand.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) 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/commands/TypeHierarchyCommand.java index 7fe2fba2d5..ef13b4987f 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/commands/TypeHierarchyCommand.java @@ -131,12 +131,19 @@ private static TypeHierarchyItem toTypeHierarchyItem(IType type) throws JavaMode item.setRange(location.getRange()); item.setUri(location.getUri()); item.setSelectionRange(selectLocation.getRange()); - item.setName(JDTUtils.getName(type)); - item.setKind(DocumentSymbolHandler.mapKind(type)); - IPackageFragment packageFragment = type.getPackageFragment(); - if (packageFragment != null) { - item.setDetail(packageFragment.getElementName()); + String fullyQualifiedName = type.getFullyQualifiedParameterizedName(); + int index = fullyQualifiedName.lastIndexOf('.'); + if (index >= 1 && index < fullyQualifiedName.length() - 1 && !type.isAnonymous()) { + item.setName(fullyQualifiedName.substring(index + 1)); + item.setDetail(fullyQualifiedName.substring(0, index)); + } else { + item.setName(JDTUtils.getName(type)); + IPackageFragment packageFragment = type.getPackageFragment(); + if (packageFragment != null) { + item.setDetail(packageFragment.getElementName()); + } } + item.setKind(DocumentSymbolHandler.mapKind(type)); item.setDeprecated(JDTUtils.isDeprecated(type)); item.setData(type.getHandleIdentifier()); return item; From 7269ba8a48a709265efbdae60b54f4633cfbf4b3 Mon Sep 17 00:00:00 2001 From: Shi Chen Date: Wed, 3 Mar 2021 14:22:46 +0800 Subject: [PATCH 08/10] Support Anonymous classes Signed-off-by: Shi Chen --- .../commands/TypeHierarchyCommand.java | 23 +++++++++++++++---- .../commands/TypeHierarchyCommandTest.java | 4 ++-- 2 files changed, 21 insertions(+), 6 deletions(-) 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/commands/TypeHierarchyCommand.java index ef13b4987f..b8a736cda8 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/commands/TypeHierarchyCommand.java @@ -24,9 +24,11 @@ import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeHierarchy; import org.eclipse.jdt.core.ITypeRoot; +import org.eclipse.jdt.core.JavaCore; 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.JavaLanguageServerPlugin; import org.eclipse.jdt.ls.core.internal.handlers.DocumentSymbolHandler; @@ -53,7 +55,7 @@ public TypeHierarchyItem typeHierarchy(TypeHierarchyParams params, IProgressMoni String uri = textDocument.getUri(); TypeHierarchyDirection direction = params.getDirection(); int resolve = params.getResolve(); - return getTypeHierarchy(uri, position, direction, resolve, monitor); + return getTypeHierarchy(uri, position, direction, resolve, null, monitor); } public TypeHierarchyItem resolveTypeHierarchy(ResolveTypeHierarchyItemParams params, IProgressMonitor monitor) { @@ -72,15 +74,28 @@ public TypeHierarchyItem resolveTypeHierarchy(ResolveTypeHierarchyItemParams par String uri = item.getUri(); TypeHierarchyDirection direction = params.getDirection(); int resolve = params.getResolve(); - return getTypeHierarchy(uri, position, direction, resolve, monitor); + return getTypeHierarchy(uri, position, direction, resolve, item, monitor); } - private TypeHierarchyItem getTypeHierarchy(String uri, Position position, TypeHierarchyDirection direction, int resolve, IProgressMonitor 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; } try { - IType type = getType(uri, position, monitor); + 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); if (item == null) { return null; 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 index 25e410efaf..4baeef1059 100644 --- 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 @@ -82,7 +82,7 @@ public void testSuperTypeHierarchy() throws Exception { assertEquals(item.getParents().size(), 2); TypeHierarchyItem builder = item.getParents().get(0); assertNotNull(builder); - assertEquals(builder.getName(), "Builder"); + assertEquals(builder.getName(), "Builder<>"); assertNull(builder.getParents()); TypeHierarchyItem object = item.getParents().get(1); assertNotNull(object); @@ -103,7 +103,7 @@ public void testSubTypeHierarchy() throws Exception { params.setPosition(position); TypeHierarchyItem item = fCommand.typeHierarchy(params, monitor); assertNotNull(item); - assertEquals(item.getName(), "Builder"); + assertEquals(item.getName(), "Builder<>"); assertNull(item.getParents()); assertEquals(item.getChildren().size(), 9); for (TypeHierarchyItem child : item.getChildren()) { From 83af7e866798010d1ddb5dd9ee72599806384641 Mon Sep 17 00:00:00 2001 From: Shi Chen Date: Wed, 3 Mar 2021 15:04:24 +0800 Subject: [PATCH 09/10] fix tests Signed-off-by: Shi Chen --- .../ls/core/internal/commands/TypeHierarchyCommandTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 4baeef1059..b47bc05fbd 100644 --- 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 @@ -82,7 +82,7 @@ public void testSuperTypeHierarchy() throws Exception { assertEquals(item.getParents().size(), 2); TypeHierarchyItem builder = item.getParents().get(0); assertNotNull(builder); - assertEquals(builder.getName(), "Builder<>"); + assertEquals(builder.getName(), "Builder"); assertNull(builder.getParents()); TypeHierarchyItem object = item.getParents().get(1); assertNotNull(object); @@ -103,7 +103,7 @@ public void testSubTypeHierarchy() throws Exception { params.setPosition(position); TypeHierarchyItem item = fCommand.typeHierarchy(params, monitor); assertNotNull(item); - assertEquals(item.getName(), "Builder<>"); + assertEquals(item.getName(), "Builder"); assertNull(item.getParents()); assertEquals(item.getChildren().size(), 9); for (TypeHierarchyItem child : item.getChildren()) { From 960db14fdca4ac74db5a226f0ad55be35742f22a Mon Sep 17 00:00:00 2001 From: Shi Chen Date: Wed, 10 Mar 2021 10:46:48 +0800 Subject: [PATCH 10/10] fix display name of BinaryType Signed-off-by: Shi Chen --- .../jdt/ls/core/internal/commands/TypeHierarchyCommand.java | 2 +- .../jdt/ls/core/internal/commands/TypeHierarchyCommandTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/commands/TypeHierarchyCommand.java index b8a736cda8..16434ba867 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/commands/TypeHierarchyCommand.java @@ -146,7 +146,7 @@ private static TypeHierarchyItem toTypeHierarchyItem(IType type) throws JavaMode item.setRange(location.getRange()); item.setUri(location.getUri()); item.setSelectionRange(selectLocation.getRange()); - String fullyQualifiedName = type.getFullyQualifiedParameterizedName(); + String fullyQualifiedName = type.getFullyQualifiedName(); int index = fullyQualifiedName.lastIndexOf('.'); if (index >= 1 && index < fullyQualifiedName.length() - 1 && !type.isAnonymous()) { item.setName(fullyQualifiedName.substring(index + 1)); 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 index b47bc05fbd..6b3345e9fb 100644 --- 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 @@ -77,7 +77,7 @@ public void testSuperTypeHierarchy() throws Exception { params.setPosition(position); TypeHierarchyItem item = fCommand.typeHierarchy(params, monitor); assertNotNull(item); - assertEquals(item.getName(), "FooBuilder"); + assertEquals(item.getName(), "CallHierarchy$FooBuilder"); assertNull(item.getChildren()); assertEquals(item.getParents().size(), 2); TypeHierarchyItem builder = item.getParents().get(0);