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 2d68b3d0ac..0b4860da23 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 @@ -35,7 +35,7 @@ import org.eclipse.jdt.ls.core.internal.JDTUtils.LocationType; 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.jdt.ls.core.internal.handlers.SymbolUtils; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; @@ -184,7 +184,7 @@ private static TypeHierarchyItem toTypeHierarchyItem(IMember member, boolean exc item.setDetail(packageFragment.getElementName()); } } - item.setKind(excludeMember ? SymbolKind.Null : DocumentSymbolHandler.mapKind(type)); + item.setKind(excludeMember ? SymbolKind.Null : SymbolUtils.mapKind(type)); item.setDeprecated(JDTUtils.isDeprecated(member)); Map data = new HashMap<>(); data.put("element", member.getHandleIdentifier()); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CallHierarchyHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CallHierarchyHandler.java index 162d6f1e3b..2c3094546e 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CallHierarchyHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CallHierarchyHandler.java @@ -319,7 +319,7 @@ private CallHierarchyItem toCallHierarchyItem(IMember member) throws JavaModelEx String uri = fullLocation.getUri(); CallHierarchyItem item = new CallHierarchyItem(); item.setName(JDTUtils.getName(member)); - item.setKind(DocumentSymbolHandler.mapKind(member)); + item.setKind(SymbolUtils.mapKind(member)); item.setRange(range); item.setSelectionRange(getLocation(member, LocationType.NAME_RANGE).getRange()); item.setUri(uri); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/DocumentSymbolHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/DocumentSymbolHandler.java index 88a2ed1d65..464e454af8 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/DocumentSymbolHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/DocumentSymbolHandler.java @@ -20,11 +20,15 @@ import static org.eclipse.jdt.core.IJavaElement.PACKAGE_DECLARATION; import static org.eclipse.jdt.core.IJavaElement.PACKAGE_FRAGMENT; import static org.eclipse.jdt.core.IJavaElement.TYPE; -import static org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore.ALL_DEFAULT; -import static org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore.M_APP_RETURNTYPE; -import static org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore.ROOT_VARIABLE; -import static org.eclipse.jdt.ls.core.internal.JDTUtils.LocationType.FULL_RANGE; +import static org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore.F_POST_QUALIFIED; +import static org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore.M_POST_QUALIFIED; import static org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin.logInfo; +import static org.eclipse.jdt.ls.core.internal.handlers.SymbolUtils.filter; +import static org.eclipse.jdt.ls.core.internal.handlers.SymbolUtils.getDetail; +import static org.eclipse.jdt.ls.core.internal.handlers.SymbolUtils.getName; +import static org.eclipse.jdt.ls.core.internal.handlers.SymbolUtils.getRange; +import static org.eclipse.jdt.ls.core.internal.handlers.SymbolUtils.getSelectionRange; +import static org.eclipse.jdt.ls.core.internal.handlers.SymbolUtils.mapKind; import java.util.ArrayList; import java.util.Arrays; @@ -39,15 +43,12 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; -import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.IClassFile; -import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IMember; -import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IParent; import org.eclipse.jdt.core.ISourceRange; 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; @@ -90,12 +91,12 @@ import org.eclipse.lsp4j.SymbolKind; import org.eclipse.lsp4j.SymbolTag; import org.eclipse.lsp4j.jsonrpc.messages.Either; +import org.eclipse.lsp4j.jsonrpc.validation.NonNull; import org.eclipse.xtext.xbase.lib.Exceptions; +import org.eclipse.xtext.xbase.lib.Pure; public class DocumentSymbolHandler { - private static Range DEFAULT_RANGE = new Range(new Position(0, 0), new Position(0, 0)); - - private PreferenceManager preferenceManager; + PreferenceManager preferenceManager; private static IScanner fScanner; @@ -103,6 +104,15 @@ public DocumentSymbolHandler(PreferenceManager preferenceManager) { this.preferenceManager = preferenceManager; } + public List extendedDocumentSymbol(DocumentSymbolParams params, IProgressMonitor monitor) { + ITypeRoot unit = JDTUtils.resolveTypeRoot(params.getTextDocument().getUri()); + if (unit == null || !unit.exists()) { + return Collections.emptyList(); + } + List symbols = getHierarchicalOutline(unit, monitor, true); + return symbols.stream().map(s -> (ExtendedDocumentSymbol) s).toList(); + } + public List> documentSymbol(DocumentSymbolParams params, IProgressMonitor monitor) { ITypeRoot unit = JDTUtils.resolveTypeRoot(params.getTextDocument().getUri()); @@ -111,7 +121,7 @@ public List> documentSymbol(DocumentSy } if (preferenceManager.getClientPreferences().isHierarchicalDocumentSymbolSupported()) { - List symbols = this.getHierarchicalOutline(unit, monitor); + List symbols = this.getHierarchicalOutline(unit, monitor, false); return symbols.stream().map(Either::forRight).collect(toList()); } else { SymbolInformation[] elements = this.getOutline(unit, monitor); @@ -178,7 +188,7 @@ private void collectChildren(ITypeRoot unit, IJavaElement[] elements, ArrayList< } } - private List getHierarchicalOutline(ITypeRoot unit, IProgressMonitor monitor) { + List getHierarchicalOutline(ITypeRoot unit, IProgressMonitor monitor, boolean includeInherited) { try { if (unit instanceof IClassFile && unit.getSourceRange() == null) { // no source attached return getHierarchicalOutlineFromDecompiledSource(unit, monitor); @@ -197,7 +207,7 @@ private List getHierarchicalOutline(ITypeRoot unit, IProgressMon scanner.resetTo(shift, shift + sourceRange.getLength()); } } - return childrenStream.map(child -> toDocumentSymbol(child, unit, monitor)).filter(Objects::nonNull).collect(Collectors.toList()); + return childrenStream.map(child -> toDocumentSymbol(child, unit, monitor, includeInherited)).filter(Objects::nonNull).collect(Collectors.toList()); } catch (OperationCanceledException e) { logInfo("User abort while collecting the document symbols."); } catch (JavaModelException e) { @@ -210,7 +220,7 @@ private List getHierarchicalOutline(ITypeRoot unit, IProgressMon return emptyList(); } - private DocumentSymbol toDocumentSymbol(IJavaElement unit, ITypeRoot root, IProgressMonitor monitor) { + private DocumentSymbol toDocumentSymbol(IJavaElement unit, ITypeRoot root, IProgressMonitor monitor, boolean includeInherited) { int type = unit.getElementType(); if (type != TYPE && type != FIELD && type != METHOD && type != PACKAGE_DECLARATION && type != COMPILATION_UNIT && type != PACKAGE_FRAGMENT) { return null; @@ -221,7 +231,7 @@ private DocumentSymbol toDocumentSymbol(IJavaElement unit, ITypeRoot root, IProg if (monitor.isCanceled()) { throw new OperationCanceledException("User abort"); } - DocumentSymbol symbol = new DocumentSymbol(); + DocumentSymbol symbol = includeInherited ? new ExtendedDocumentSymbol() : new DocumentSymbol(); try { String name = getName(unit); symbol.setName(name); @@ -256,12 +266,35 @@ private DocumentSymbol toDocumentSymbol(IJavaElement unit, ITypeRoot root, IProg symbol.setDeprecated(true); } } - symbol.setDetail(getDetail(unit, name)); + if (symbol instanceof ExtendedDocumentSymbol) { + symbol.setDetail(getDetail(unit, name, M_POST_QUALIFIED | F_POST_QUALIFIED)); + } else { + symbol.setDetail(getDetail(unit, name)); + } if (unit instanceof IParent parent) { + List children = new ArrayList<>(); + children.addAll(Arrays.asList(filter(parent.getChildren()))); + if (symbol instanceof ExtendedDocumentSymbol) { + Location loc = JDTUtils.toLocation(unit); + if (loc != null) { + ((ExtendedDocumentSymbol) symbol).setUri(loc.getUri()); + } + if (unit instanceof IType tp) { + ITypeHierarchy supertypeHierarchy = tp.newSupertypeHierarchy(monitor); + if (monitor.isCanceled()) { + throw new OperationCanceledException(); + } + IType[] superClasses = supertypeHierarchy.getAllSuperclasses(tp); + for (IType superType : superClasses) { + if (!"java.lang.Object".equals(superType.getFullyQualifiedName())) { + children.addAll(Arrays.asList(filter(superType.getChildren()))); + } + } + } + } //@formatter:off - IJavaElement[] children = filter(parent.getChildren()); - symbol.setChildren(Stream.of(children) - .map(child -> toDocumentSymbol(child, null, monitor)) + symbol.setChildren(children.stream() + .map(child -> toDocumentSymbol(child, null, monitor, includeInherited)) .filter(Objects::nonNull) .collect(Collectors.toList())); //@formatter:off @@ -272,120 +305,6 @@ private DocumentSymbol toDocumentSymbol(IJavaElement unit, ITypeRoot root, IProg return symbol; } - private String getName(IJavaElement element) { - String name = JavaElementLabelsCore.getElementLabel(element, ALL_DEFAULT); - return name == null ? element.getElementName() : name; - } - - private Range getRange(IJavaElement element) throws JavaModelException { - Location location = JDTUtils.toLocation(element, FULL_RANGE); - return location == null ? DEFAULT_RANGE : location.getRange(); - } - - private Range getSelectionRange(IJavaElement element) throws JavaModelException { - Location location = JDTUtils.toLocation(element); - return location == null ? DEFAULT_RANGE : location.getRange(); - } - - private String getDetail(IJavaElement element, String name) { - String nameWithDetails = JavaElementLabelsCore.getElementLabel(element, ALL_DEFAULT | M_APP_RETURNTYPE | ROOT_VARIABLE); - if (nameWithDetails != null && nameWithDetails.startsWith(name)) { - return nameWithDetails.substring(name.length()); - } - return ""; - } - - private IJavaElement[] filter(IJavaElement[] elements) { - return Stream.of(elements) - .filter(e -> (!isInitializer(e) && !isSyntheticElement(e))) - .toArray(IJavaElement[]::new); - } - - private boolean isInitializer(IJavaElement element) { - if (element.getElementType() == IJavaElement.METHOD) { - String name = element.getElementName(); - if ((name != null && name.indexOf('<') >= 0)) { - return true; - } - } - return false; - } - - private boolean isSyntheticElement(IJavaElement element) { - if (!(element instanceof IMember)) { - return false; - } - IMember member= (IMember)element; - if (!(member.isBinary())) { - return false; - } - try { - return Flags.isSynthetic(member.getFlags()); - } catch (JavaModelException e) { - return false; - } - } - - public static SymbolKind mapKind(IJavaElement element) { - switch (element.getElementType()) { - case IJavaElement.TYPE: - try { - IType type = (IType)element; - if (type.isInterface()) { - return SymbolKind.Interface; - } - else if (type.isEnum()) { - return SymbolKind.Enum; - } - } catch (JavaModelException ignore) { - } - return SymbolKind.Class; - case IJavaElement.ANNOTATION: - return SymbolKind.Property; // TODO: find a better mapping - case IJavaElement.CLASS_FILE: - case IJavaElement.COMPILATION_UNIT: - return SymbolKind.File; - case IJavaElement.FIELD: - IField field = (IField) element; - try { - if (field.isEnumConstant()) { - return SymbolKind.EnumMember; - } - int flags = field.getFlags(); - if (Flags.isStatic(flags) && Flags.isFinal(flags)) { - return SymbolKind.Constant; - } - } catch (JavaModelException ignore) { - } - return SymbolKind.Field; - case IJavaElement.IMPORT_CONTAINER: - case IJavaElement.IMPORT_DECLARATION: - //should we return SymbolKind.Namespace? - case IJavaElement.JAVA_MODULE: - return SymbolKind.Module; - case IJavaElement.INITIALIZER: - return SymbolKind.Constructor; - case IJavaElement.LOCAL_VARIABLE: - return SymbolKind.Variable; - case IJavaElement.TYPE_PARAMETER: - return SymbolKind.TypeParameter; - case IJavaElement.METHOD: - try { - // TODO handle `IInitializer`. What should be the `SymbolKind`? - if (element instanceof IMethod method && method.isConstructor()) { - return SymbolKind.Constructor; - } - return SymbolKind.Method; - } catch (JavaModelException e) { - return SymbolKind.Method; - } - case IJavaElement.PACKAGE_DECLARATION: - case IJavaElement.PACKAGE_FRAGMENT: - return SymbolKind.Package; - } - return SymbolKind.String; - } - private static IScanner getScanner() { if (fScanner == null) { fScanner = ToolFactory.createScanner(true, false, false, true); @@ -660,4 +579,51 @@ private boolean containsModifier(List modifiers, String target) { return false; } } + + public static class ExtendedDocumentSymbol extends DocumentSymbol { + /** + * The uri of the document of this symbol. + */ + @NonNull + private String uri; + + /** + * The uri of the document of this symbol. + */ + public void setUri(@NonNull String uri) { + this.uri = uri; + } + + /** + * The uri of the document of this symbol. + */ + @NonNull + @Pure + public String getUri() { + return this.uri; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + Objects.hash(uri); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ExtendedDocumentSymbol other = (ExtendedDocumentSymbol) obj; + return Objects.equals(uri, other.uri); + } + } } 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 6e2842ee55..9afc5240ce 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 @@ -56,6 +56,7 @@ import org.eclipse.jdt.ls.core.internal.ServiceStatus; import org.eclipse.jdt.ls.core.internal.codemanipulation.GenerateGetterSetterOperation.AccessorField; import org.eclipse.jdt.ls.core.internal.handlers.CodeActionHandler.CodeActionData; +import org.eclipse.jdt.ls.core.internal.handlers.DocumentSymbolHandler.ExtendedDocumentSymbol; import org.eclipse.jdt.ls.core.internal.handlers.ExtractInterfaceHandler.CheckExtractInterfaceResponse; import org.eclipse.jdt.ls.core.internal.handlers.FindLinksHandler.FindLinksParams; import org.eclipse.jdt.ls.core.internal.handlers.GenerateAccessorsHandler.AccessorCodeActionParams; @@ -749,6 +750,16 @@ public CompletableFuture>> docume }); } + @Override + public CompletableFuture> extendedDocumentSymbol(DocumentSymbolParams params) { + logInfo(">> java/extendedDocumentSymbol"); + DocumentSymbolHandler handler = new DocumentSymbolHandler(preferenceManager); + return computeAsync((monitor) -> { + waitForLifecycleJobs(monitor); + return handler.extendedDocumentSymbol(params, monitor); + }); + } + /* (non-Javadoc) * @see org.eclipse.lsp4j.services.TextDocumentService#codeAction(org.eclipse.lsp4j.CodeActionParams) */ diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/SymbolUtils.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/SymbolUtils.java new file mode 100644 index 0000000000..361a7a4d29 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/SymbolUtils.java @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat Inc. 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: + * Gayan Perera (gayanper@gmail.com) - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ls.core.internal.handlers; + +import static org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore.ALL_DEFAULT; +import static org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore.M_APP_RETURNTYPE; +import static org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore.ROOT_VARIABLE; +import static org.eclipse.jdt.ls.core.internal.JDTUtils.LocationType.FULL_RANGE; + +import java.util.stream.Stream; + +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.IField; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IMember; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore; +import org.eclipse.jdt.ls.core.internal.JDTUtils; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.SymbolKind; + +public final class SymbolUtils { + private static final Range DEFAULT_RANGE = new Range(new Position(0, 0), new Position(0, 0)); + + static IJavaElement[] filter(IJavaElement[] elements) { + return Stream.of(elements).filter(e -> (!SymbolUtils.isInitializer(e) && !SymbolUtils.isSyntheticElement(e))).toArray(IJavaElement[]::new); + } + + private static boolean isInitializer(IJavaElement element) { + if (element.getElementType() == IJavaElement.METHOD) { + String name = element.getElementName(); + if ((name != null && name.indexOf('<') >= 0)) { + return true; + } + } + return false; + } + + private static boolean isSyntheticElement(IJavaElement element) { + if (!(element instanceof IMember)) { + return false; + } + IMember member = (IMember) element; + if (!(member.isBinary())) { + return false; + } + try { + return Flags.isSynthetic(member.getFlags()); + } catch (JavaModelException e) { + return false; + } + } + + public static SymbolKind mapKind(IJavaElement element) { + switch (element.getElementType()) { + case IJavaElement.TYPE: + try { + IType type = (IType) element; + if (type.isInterface()) { + return SymbolKind.Interface; + } else if (type.isEnum()) { + return SymbolKind.Enum; + } + } catch (JavaModelException ignore) { + } + return SymbolKind.Class; + case IJavaElement.ANNOTATION: + return SymbolKind.Property; // TODO: find a better mapping + case IJavaElement.CLASS_FILE: + case IJavaElement.COMPILATION_UNIT: + return SymbolKind.File; + case IJavaElement.FIELD: + IField field = (IField) element; + try { + if (field.isEnumConstant()) { + return SymbolKind.EnumMember; + } + int flags = field.getFlags(); + if (Flags.isStatic(flags) && Flags.isFinal(flags)) { + return SymbolKind.Constant; + } + } catch (JavaModelException ignore) { + } + return SymbolKind.Field; + case IJavaElement.IMPORT_CONTAINER: + case IJavaElement.IMPORT_DECLARATION: + //should we return SymbolKind.Namespace? + case IJavaElement.JAVA_MODULE: + return SymbolKind.Module; + case IJavaElement.INITIALIZER: + return SymbolKind.Constructor; + case IJavaElement.LOCAL_VARIABLE: + return SymbolKind.Variable; + case IJavaElement.TYPE_PARAMETER: + return SymbolKind.TypeParameter; + case IJavaElement.METHOD: + try { + // TODO handle `IInitializer`. What should be the `SymbolKind`? + if (element instanceof IMethod method && method.isConstructor()) { + return SymbolKind.Constructor; + } + return SymbolKind.Method; + } catch (JavaModelException e) { + return SymbolKind.Method; + } + case IJavaElement.PACKAGE_DECLARATION: + case IJavaElement.PACKAGE_FRAGMENT: + return SymbolKind.Package; + } + return SymbolKind.String; + } + + static String getName(IJavaElement element) { + String name = JavaElementLabelsCore.getElementLabel(element, ALL_DEFAULT); + return name == null ? element.getElementName() : name; + } + + static Range getRange(IJavaElement element) throws JavaModelException { + Location location = JDTUtils.toLocation(element, FULL_RANGE); + return location == null ? DEFAULT_RANGE : location.getRange(); + } + + static Range getSelectionRange(IJavaElement element) throws JavaModelException { + Location location = JDTUtils.toLocation(element); + return location == null ? DEFAULT_RANGE : location.getRange(); + } + + static String getDetail(IJavaElement element, String name) { + return constructDetail(element, name, ALL_DEFAULT | M_APP_RETURNTYPE | ROOT_VARIABLE); + } + + static String getDetail(IJavaElement element, String name, long additionalFlags) { + return constructDetail(element, name, ALL_DEFAULT | ROOT_VARIABLE | additionalFlags); + } + + private static String constructDetail(IJavaElement element, String name, long flags) { + String nameWithDetails = JavaElementLabelsCore.getElementLabel(element, flags); + if (nameWithDetails != null && nameWithDetails.startsWith(name)) { + return nameWithDetails.substring(name.length()); + } + return ""; + } + +} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/TypeHierarchyHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/TypeHierarchyHandler.java index af57ab43a2..453ea80e6f 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/TypeHierarchyHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/TypeHierarchyHandler.java @@ -252,7 +252,7 @@ private static TypeHierarchyItem toTypeHierarchyItem(IMember member, boolean exc detail = packageFragment.getElementName(); } } - SymbolKind kind = excludeMember ? SymbolKind.Null : DocumentSymbolHandler.mapKind(type); + SymbolKind kind = excludeMember ? SymbolKind.Null : SymbolUtils.mapKind(type); List tags = new ArrayList<>(); if (JDTUtils.isDeprecated(member)) { tags.add(SymbolTag.Deprecated); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/lsp/JavaProtocolExtensions.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/lsp/JavaProtocolExtensions.java index a22cfcdf0e..0054df9524 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/lsp/JavaProtocolExtensions.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/lsp/JavaProtocolExtensions.java @@ -17,6 +17,7 @@ import org.eclipse.jdt.ls.core.internal.BuildWorkspaceStatus; import org.eclipse.jdt.ls.core.internal.codemanipulation.GenerateGetterSetterOperation.AccessorField; +import org.eclipse.jdt.ls.core.internal.handlers.DocumentSymbolHandler.ExtendedDocumentSymbol; import org.eclipse.jdt.ls.core.internal.handlers.ExtractInterfaceHandler.CheckExtractInterfaceResponse; import org.eclipse.jdt.ls.core.internal.handlers.FindLinksHandler.FindLinksParams; import org.eclipse.jdt.ls.core.internal.handlers.GenerateAccessorsHandler.AccessorCodeActionParams; @@ -40,6 +41,7 @@ import org.eclipse.jdt.ls.core.internal.handlers.WorkspaceSymbolHandler.SearchSymbolParams; import org.eclipse.jdt.ls.core.internal.text.correction.ChangeSignatureInfo; import org.eclipse.lsp4j.CodeActionParams; +import org.eclipse.lsp4j.DocumentSymbolParams; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.SymbolInformation; import org.eclipse.lsp4j.TextDocumentIdentifier; @@ -154,4 +156,11 @@ public interface JavaProtocolExtensions { @JsonNotification void validateDocument(ValidateDocumentParams params); + + /** + * List all the symbols in the document (class) hierarchy. + */ + @JsonRequest + CompletableFuture> extendedDocumentSymbol(DocumentSymbolParams params); + }