This is an automated email from the ASF dual-hosted git repository.

dbalek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 0f2565c  GR-33089: Enrich Java Outline view by more details. (#3263)
0f2565c is described below

commit 0f2565c436deec16d518df47d5161426bc86cfe9
Author: Dusan Balek <[email protected]>
AuthorDate: Mon Oct 25 14:58:59 2021 +0200

    GR-33089: Enrich Java Outline view by more details. (#3263)
---
 .../netbeans/modules/java/lsp/server/Utils.java    | 135 +++++++++++++++++++--
 .../lsp/server/protocol/CodeActionsProvider.java   |  74 ++---------
 .../server/protocol/TextDocumentServiceImpl.java   | 109 ++++++++++++-----
 .../java/lsp/server/protocol/ServerTest.java       |  24 +---
 4 files changed, 213 insertions(+), 129 deletions(-)

diff --git 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java
index ec5af37..46ec105 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java
@@ -19,21 +19,28 @@
 package org.netbeans.modules.java.lsp.server;
 
 import com.google.gson.stream.JsonWriter;
+import com.sun.source.tree.ClassTree;
 import com.sun.source.tree.CompilationUnitTree;
 import com.sun.source.tree.LineMap;
+import com.sun.source.tree.MethodTree;
 import com.sun.source.tree.Tree;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
+import com.sun.source.tree.VariableTree;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.io.StringWriter;
 import java.net.MalformedURLException;
 import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Properties;
+import java.util.Iterator;
+import java.util.List;
+import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
 import javax.swing.text.StyledDocument;
 import org.eclipse.lsp4j.Position;
 import org.eclipse.lsp4j.Range;
@@ -41,11 +48,10 @@ import org.eclipse.lsp4j.SymbolKind;
 import org.netbeans.api.editor.document.LineDocument;
 import org.netbeans.api.editor.document.LineDocumentUtils;
 import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.modules.editor.java.Utilities;
 import org.openide.cookies.EditorCookie;
 import org.openide.filesystems.FileObject;
-import org.openide.filesystems.FileUtil;
 import org.openide.filesystems.URLMapper;
-import org.openide.modules.Places;
 import org.openide.text.NbDocument;
 import org.openide.util.Exceptions;
 
@@ -95,6 +101,97 @@ public class Utils {
         }
     }
 
+    public static String label(CompilationInfo info, Element e, boolean fqn) {
+        switch (e.getKind()) {
+            case PACKAGE:
+                PackageElement pe = (PackageElement) e;
+                return fqn ? pe.getQualifiedName().toString() : 
pe.getSimpleName().toString();
+            case CLASS:
+            case INTERFACE:
+            case ENUM:
+            case ANNOTATION_TYPE:
+                TypeElement te = (TypeElement) e;
+                StringBuilder sb = new StringBuilder();
+                sb.append(fqn ? te.getQualifiedName() : te.getSimpleName());
+                List<? extends TypeParameterElement> typeParams = 
te.getTypeParameters();
+                if (typeParams != null && !typeParams.isEmpty()) {
+                    sb.append("<"); // NOI18N
+                    for(Iterator<? extends TypeParameterElement> it = 
typeParams.iterator(); it.hasNext();) {
+                        TypeParameterElement tp = it.next();
+                        sb.append(tp.getSimpleName());
+                        List<? extends TypeMirror> bounds = tp.getBounds();
+                        if (!bounds.isEmpty()) {
+                            if (bounds.size() > 1 || 
!"java.lang.Object".equals(bounds.get(0).toString())) { // NOI18N
+                                sb.append(" extends "); // NOI18N
+                                for (Iterator<? extends TypeMirror> bIt = 
bounds.iterator(); bIt.hasNext();) {
+                                    sb.append(Utilities.getTypeName(info, 
bIt.next(), fqn));
+                                    if (bIt.hasNext()) {
+                                        sb.append(" & "); // NOI18N
+                                    }
+                                }
+                            }
+                        }
+                        if (it.hasNext()) {
+                            sb.append(", "); // NOI18N
+                        }
+                    }
+                    sb.append(">"); // NOI18N
+                }
+                return sb.toString();
+            case FIELD:
+            case ENUM_CONSTANT:
+                return e.getSimpleName().toString();
+            case CONSTRUCTOR:
+            case METHOD:
+                ExecutableElement ee = (ExecutableElement) e;
+                sb = new StringBuilder();
+                if (ee.getKind() == ElementKind.CONSTRUCTOR) {
+                    sb.append(ee.getEnclosingElement().getSimpleName());
+                } else {
+                    sb.append(ee.getSimpleName());
+                }
+                sb.append("("); // NOI18N
+                for (Iterator<? extends VariableElement> it = 
ee.getParameters().iterator(); it.hasNext();) {
+                    VariableElement param = it.next();
+                    if (!it.hasNext() && ee.isVarArgs() && 
param.asType().getKind() == TypeKind.ARRAY) {
+                        sb.append(Utilities.getTypeName(info, ((ArrayType) 
param.asType()).getComponentType(), fqn));
+                        sb.append("...");
+                    } else {
+                        sb.append(Utilities.getTypeName(info, param.asType(), 
fqn));
+                    }
+                    sb.append(" "); // NOI18N
+                    sb.append(param.getSimpleName());
+                    if (it.hasNext()) {
+                        sb.append(", "); // NOI18N
+                    }
+                }
+                sb.append(")"); // NOI18N
+                return sb.toString();
+        }
+        return null;
+    }
+
+    public static String detail(CompilationInfo info, Element e, boolean fqn) {
+        switch (e.getKind()) {
+            case FIELD:
+                StringBuilder sb = new StringBuilder();
+                sb.append(": " );
+                sb.append(Utilities.getTypeName(info, e.asType(), fqn));
+                return sb.toString();
+            case METHOD:
+                sb = new StringBuilder();
+                TypeMirror rt = ((ExecutableElement) e).getReturnType();
+                if (rt.getKind() == TypeKind.VOID) {
+                    sb.append(": void" );
+                } else {
+                    sb.append(": ");
+                    sb.append(Utilities.getTypeName(info, rt, fqn));
+                }
+                return sb.toString();
+        }
+        return null;
+    }
+
     public static Range treeRange(CompilationInfo info, Tree tree) {
         long start = 
info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(),
 tree);
         long end   = 
info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), 
tree);
@@ -105,6 +202,26 @@ public class Utils {
                          createPosition(info.getCompilationUnit(), (int) end));
     }
 
+    public static Range selectionRange(CompilationInfo info, Tree tree) {
+        int[] span = null;
+        switch (tree.getKind()) {
+            case CLASS:
+                span = info.getTreeUtilities().findNameSpan((ClassTree) tree);
+                break;
+            case METHOD:
+                span = info.getTreeUtilities().findNameSpan((MethodTree)tree);
+                break;
+            case VARIABLE:
+                span = 
info.getTreeUtilities().findNameSpan((VariableTree)tree);
+                break;
+        }
+        if (span == null) {
+            return null;
+        }
+        return new Range(createPosition(info.getCompilationUnit(), (int) 
span[0]),
+                         createPosition(info.getCompilationUnit(), (int) 
span[1]));
+    }
+
     public static Position createPosition(CompilationUnitTree cut, int offset) 
{
         return createPosition(cut.getLineMap(), offset);
     }
diff --git 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java
 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java
index 50c8b76..db57677 100644
--- 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java
+++ 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java
@@ -20,7 +20,6 @@ package org.netbeans.modules.java.lsp.server.protocol;
 
 import com.sun.source.tree.LineMap;
 import java.util.Arrays;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -29,11 +28,7 @@ import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.TypeParameterElement;
 import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
 import org.eclipse.lsp4j.CodeAction;
 import org.eclipse.lsp4j.CodeActionParams;
 import org.eclipse.lsp4j.Command;
@@ -41,7 +36,7 @@ import org.eclipse.lsp4j.Position;
 import org.eclipse.xtext.xbase.lib.Pure;
 import org.netbeans.api.java.source.CompilationInfo;
 import org.netbeans.api.java.source.ElementHandle;
-import org.netbeans.modules.editor.java.Utilities;
+import org.netbeans.modules.java.lsp.server.Utils;
 import org.netbeans.modules.java.source.ElementHandleAccessor;
 import org.netbeans.modules.parsing.api.ResultIterator;
 
@@ -99,33 +94,7 @@ public abstract class CodeActionsProvider {
     }
 
     protected static String createLabel(CompilationInfo info, TypeElement e, 
boolean fqn) {
-        StringBuilder sb = new StringBuilder();
-        sb.append(fqn ? e.getQualifiedName() : e.getSimpleName());
-        List<? extends TypeParameterElement> typeParams = 
e.getTypeParameters();
-        if (typeParams != null && !typeParams.isEmpty()) {
-            sb.append("<"); // NOI18N
-            for(Iterator<? extends TypeParameterElement> it = 
typeParams.iterator(); it.hasNext();) {
-                TypeParameterElement tp = it.next();
-                sb.append(tp.getSimpleName());
-                List<? extends TypeMirror> bounds = tp.getBounds();
-                if (!bounds.isEmpty()) {
-                    if (bounds.size() > 1 || 
!"java.lang.Object".equals(bounds.get(0).toString())) { // NOI18N
-                        sb.append(" extends "); // NOI18N
-                        for (Iterator<? extends TypeMirror> bIt = 
bounds.iterator(); bIt.hasNext();) {
-                            sb.append(Utilities.getTypeName(info, bIt.next(), 
fqn));
-                            if (bIt.hasNext()) {
-                                sb.append(" & "); // NOI18N
-                            }
-                        }
-                    }
-                }
-                if (it.hasNext()) {
-                    sb.append(", "); // NOI18N
-                }
-            }
-            sb.append(">"); // NOI18N
-        }
-        return sb.toString();
+        return Utils.label(info, e, fqn);
     }
 
     protected static String createLabel(CompilationInfo info, VariableElement 
e) {
@@ -134,11 +103,9 @@ public abstract class CodeActionsProvider {
 
     protected static String createLabel(CompilationInfo info, VariableElement 
e, boolean fqn) {
         StringBuilder sb = new StringBuilder();
-        sb.append(e.getSimpleName());
-        if (e.getKind() != ElementKind.ENUM_CONSTANT) {
-            sb.append(" : "); // NOI18N
-            sb.append(Utilities.getTypeName(info, e.asType(), fqn));
-        }
+        sb.append(Utils.label(info, e, fqn));
+        sb.append(" : "); // NOI18N
+        sb.append(Utils.detail(info, e, fqn));
         return sb.toString();
     }
 
@@ -148,34 +115,9 @@ public abstract class CodeActionsProvider {
 
     protected static String createLabel(CompilationInfo info, 
ExecutableElement e, boolean fqn) {
         StringBuilder sb = new StringBuilder();
-        if (e.getKind() == ElementKind.CONSTRUCTOR) {
-            sb.append(e.getEnclosingElement().getSimpleName());
-        } else {
-            sb.append(e.getSimpleName());
-        }
-        sb.append("("); // NOI18N
-        for (Iterator<? extends VariableElement> it = 
e.getParameters().iterator(); it.hasNext();) {
-            VariableElement param = it.next();
-            if (!it.hasNext() && e.isVarArgs() && param.asType().getKind() == 
TypeKind.ARRAY) {
-                sb.append(Utilities.getTypeName(info, ((ArrayType) 
param.asType()).getComponentType(), fqn));
-                sb.append("...");
-            } else {
-                sb.append(Utilities.getTypeName(info, param.asType(), fqn));
-            }
-            sb.append(" "); // NOI18N
-            sb.append(param.getSimpleName());
-            if (it.hasNext()) {
-                sb.append(", "); // NOI18N
-            }
-        }
-        sb.append(")"); // NOI18N
-        if (e.getKind() != ElementKind.CONSTRUCTOR) {
-            TypeMirror rt = e.getReturnType();
-            if (rt.getKind() != TypeKind.VOID) {
-                sb.append(" : "); // NOI18N
-                sb.append(Utilities.getTypeName(info, e.getReturnType(), fqn));
-            }
-        }
+        sb.append(Utils.label(info, e, fqn));
+        sb.append(" : "); // NOI18N
+        sb.append(Utils.detail(info, e, fqn));
         return sb.toString();
     }
 
diff --git 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
index af201b7..7b75f94 100644
--- 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
+++ 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
@@ -22,8 +22,10 @@ import com.google.gson.Gson;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonPrimitive;
 import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
 import com.sun.source.tree.LineMap;
 import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.NewClassTree;
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.Tree.Kind;
 import com.sun.source.tree.VariableTree;
@@ -124,6 +126,7 @@ import org.eclipse.lsp4j.ResourceOperation;
 import org.eclipse.lsp4j.SignatureHelp;
 import org.eclipse.lsp4j.SignatureHelpParams;
 import org.eclipse.lsp4j.SymbolInformation;
+import org.eclipse.lsp4j.SymbolKind;
 import org.eclipse.lsp4j.TextDocumentContentChangeEvent;
 import org.eclipse.lsp4j.TextDocumentEdit;
 import org.eclipse.lsp4j.TextEdit;
@@ -745,39 +748,51 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
 
     @Override
     public CompletableFuture<List<Either<SymbolInformation, DocumentSymbol>>> 
documentSymbol(DocumentSymbolParams params) {
-        // shortcut: if the projects are not yet initialized, return empty:
-        if (server.openedProjects().getNow(null) == null) {
-            return CompletableFuture.completedFuture(Collections.emptyList());
-        }
-        JavaSource js = getJavaSource(params.getTextDocument().getUri());
-        if (js == null) {
-            return CompletableFuture.completedFuture(Collections.emptyList());
-        }
-        List<Either<SymbolInformation, DocumentSymbol>> result = new 
ArrayList<>();
-        try {
-            js.runUserActionTask(cc -> {
-                cc.toPhase(JavaSource.Phase.RESOLVED);
-                for (Element tel : cc.getTopLevelElements()) {
-                    DocumentSymbol ds = element2DocumentSymbol(cc, tel);
-                    if (ds != null)
-                        result.add(Either.forRight(ds));
-                }
-            }, true);
-        } catch (IOException ex) {
-            //TODO: include stack trace:
-            client.logMessage(new MessageParams(MessageType.Error, 
ex.getMessage()));
-        }
-
-        return CompletableFuture.completedFuture(result);
+        return server.openedProjects().thenCompose(projects -> {
+            JavaSource js = getJavaSource(params.getTextDocument().getUri());
+            if (js == null) {
+                return 
CompletableFuture.completedFuture(Collections.emptyList());
+            }
+            List<Either<SymbolInformation, DocumentSymbol>> result = new 
ArrayList<>();
+            try {
+                js.runUserActionTask(cc -> {
+                    cc.toPhase(JavaSource.Phase.RESOLVED);
+                    Trees trees = cc.getTrees();
+                    CompilationUnitTree cu = cc.getCompilationUnit();
+                    if (cu.getPackage() != null) {
+                        TreePath tp = trees.getPath(cu, cu.getPackage());
+                        Element el = trees.getElement(tp);
+                        if (el != null && el.getKind() == ElementKind.PACKAGE) 
{
+                            String name = Utils.label(cc, el, true);
+                            SymbolKind kind = 
Utils.elementKind2SymbolKind(el.getKind());
+                            Range range = Utils.treeRange(cc, tp.getLeaf());
+                            result.add(Either.forRight(new 
DocumentSymbol(name, kind, range, range)));
+                        }
+                    }
+                    for (Element tel : cc.getTopLevelElements()) {
+                        DocumentSymbol ds = element2DocumentSymbol(cc, tel);
+                        if (ds != null)
+                            result.add(Either.forRight(ds));
+                    }
+                }, true);
+            } catch (IOException ex) {
+                client.logMessage(new MessageParams(MessageType.Error, 
ex.getMessage()));
+            }
+            return CompletableFuture.completedFuture(result);
+        });
     }
 
-    private DocumentSymbol element2DocumentSymbol(CompilationInfo info, 
Element el) throws BadLocationException {
+    private static DocumentSymbol element2DocumentSymbol(CompilationInfo info, 
Element el) {
         TreePath path = info.getTrees().getPath(el);
         if (path == null)
             return null;
+        TreeUtilities tu = info.getTreeUtilities();
+        if (tu.isSynthetic(path))
+            return null;
         Range range = Utils.treeRange(info, path.getLeaf());
         if (range == null)
             return null;
+        Range selection = Utils.selectionRange(info, path.getLeaf());
         List<DocumentSymbol> children = new ArrayList<>();
         for (Element c : el.getEnclosedElements()) {
             DocumentSymbol ds = element2DocumentSymbol(info, c);
@@ -785,16 +800,44 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
                 children.add(ds);
             }
         }
-
-        String simpleName;
-
-        if (el.getKind() == ElementKind.CONSTRUCTOR) {
-            simpleName = el.getEnclosingElement().getSimpleName().toString();
-        } else {
-            simpleName = el.getSimpleName().toString();
+        if (path.getLeaf().getKind() == Kind.METHOD || 
path.getLeaf().getKind() == Kind.VARIABLE) {
+            children.addAll(getAnonymousInnerClasses(info, path));
         }
+        String name = Utils.label(info, el, false);
+        String detail = Utils.detail(info, el, false);
+        return new DocumentSymbol(name, 
Utils.elementKind2SymbolKind(el.getKind()), range, selection != null ? 
selection : range, detail, children);
+    }
 
-        return new DocumentSymbol(simpleName, 
Utils.elementKind2SymbolKind(el.getKind()), range, range, null, children);
+    private static List<DocumentSymbol> 
getAnonymousInnerClasses(CompilationInfo info, TreePath path) {
+        List<DocumentSymbol> inner = new ArrayList<>();
+        new TreePathScanner<Void, Void>() {
+            @Override
+            public Void visitNewClass(NewClassTree node, Void p) {
+                if (node.getClassBody() != null) {
+                    Range range = Utils.treeRange(info, node);
+                    if (range != null) {
+                        Range selectionRange = Utils.treeRange(info, 
node.getIdentifier());
+                        Element e = info.getTrees().getElement(new 
TreePath(getCurrentPath(), node.getClassBody()));
+                        if (e != null) {
+                            Element te = info.getTrees().getElement(new 
TreePath(getCurrentPath(), node.getIdentifier()));
+                            if (te != null) {
+                                String name = "new " + te.getSimpleName() + 
"() {...}";
+                                List<DocumentSymbol> children = new 
ArrayList<>();
+                                for (Element c : e.getEnclosedElements()) {
+                                    DocumentSymbol ds = 
element2DocumentSymbol(info, c);
+                                    if (ds != null) {
+                                        children.add(ds);
+                                    }
+                                }
+                                inner.add(new DocumentSymbol(name, 
Utils.elementKind2SymbolKind(e.getKind()), range, selectionRange, null, 
children));
+                            }
+                        }
+                    }
+                }
+                return null;
+            }
+        }.scan(path, null);
+        return inner;
     }
 
     @Override
diff --git 
a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
 
b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
index 4dadd8e..f147945 100644
--- 
a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
+++ 
b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
@@ -756,16 +756,7 @@ public class ServerTest extends NbTestCase {
                           "    line = 7\n" +
                           "    character = 5\n" +
                           "  ]\n" +
-                          "]:(Constructor:Inner:Range [\n" +
-                          "  start = Position [\n" +
-                          "    line = 4\n" +
-                          "    character = 4\n" +
-                          "  ]\n" +
-                          "  end = Position [\n" +
-                          "    line = 4\n" +
-                          "    character = 4\n" +
-                          "  ]\n" +
-                          "]:(), Method:innerMethod:Range [\n" +
+                          "]:(Method:innerMethod():Range [\n" +
                           "  start = Position [\n" +
                           "    line = 5\n" +
                           "    character = 8\n" +
@@ -774,16 +765,7 @@ public class ServerTest extends NbTestCase {
                           "    line = 6\n" +
                           "    character = 9\n" +
                           "  ]\n" +
-                          "]:()), Constructor:Test:Range [\n" +
-                          "  start = Position [\n" +
-                          "    line = 0\n" +
-                          "    character = 7\n" +
-                          "  ]\n" +
-                          "  end = Position [\n" +
-                          "    line = 0\n" +
-                          "    character = 7\n" +
-                          "  ]\n" +
-                          "]:(), Field:field:Range [\n" +
+                          "]:()), Field:field:Range [\n" +
                           "  start = Position [\n" +
                           "    line = 1\n" +
                           "    character = 4\n" +
@@ -792,7 +774,7 @@ public class ServerTest extends NbTestCase {
                           "    line = 1\n" +
                           "    character = 22\n" +
                           "  ]\n" +
-                          "]:(), Method:method:Range [\n" +
+                          "]:(), Method:method():Range [\n" +
                           "  start = Position [\n" +
                           "    line = 2\n" +
                           "    character = 4\n" +

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to