Skip to content

Commit

Permalink
Fixing LspElementUtils with anonymous classes extending an enclosing …
Browse files Browse the repository at this point in the history
…class, and speeding up the SructureElement computation.
  • Loading branch information
lahodaj committed Aug 28, 2024
1 parent 36171a7 commit 4d6ce7c
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 56 deletions.
2 changes: 1 addition & 1 deletion java/java.sourceui/nbproject/project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# under the License.
javadoc.apichanges=${basedir}/apichanges.xml
javac.compilerargs=-Xlint -Xlint:-serial
javac.source=1.8
javac.release=17
javadoc.arch=${basedir}/arch.xml
spec.version.base=1.74.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -557,27 +557,7 @@ private static void getOffset(final FileObject fo, final ElementHandle<? extends
}

if (elTree != null) {
result[1] = (int)info.getTrees().getSourcePositions().getStartPosition(cu, elTree);
result[2] = (int)info.getTrees().getSourcePositions().getEndPosition(cu, elTree);
int[] span = null;
switch(elTree.getKind()) {
case CLASS:
case INTERFACE:
case ENUM:
case ANNOTATION_TYPE:
span = info.getTreeUtilities().findNameSpan((ClassTree)elTree);
break;
case METHOD:
span = info.getTreeUtilities().findNameSpan((MethodTree)elTree);
break;
case VARIABLE:
span = info.getTreeUtilities().findNameSpan((VariableTree)elTree);
break;
}
if (span != null) {
result[3] = span[0];
result[4] = span[1];
}
fillInTreePositions(info, elTree, result);
}
}
};
Expand All @@ -586,6 +566,32 @@ private static void getOffset(final FileObject fo, final ElementHandle<? extends
}
}

static void fillInTreePositions(CompilationInfo info, Tree forTree, Object[] target) {
CompilationUnitTree cu = info.getCompilationUnit();
target[1] = (int)info.getTrees().getSourcePositions().getStartPosition(cu, forTree);
target[2] = (int)info.getTrees().getSourcePositions().getEndPosition(cu, forTree);
int[] span = null;
switch(forTree.getKind()) {
case CLASS:
case INTERFACE:
case ENUM:
case ANNOTATION_TYPE:
case RECORD:
span = info.getTreeUtilities().findNameSpan((ClassTree)forTree);
break;
case METHOD:
span = info.getTreeUtilities().findNameSpan((MethodTree)forTree);
break;
case VARIABLE:
span = info.getTreeUtilities().findNameSpan((VariableTree)forTree);
break;
}
if (span != null) {
target[3] = span[0];
target[4] = span[1];
}
}

// Private innerclasses ----------------------------------------------------

private static class FindDeclarationVisitor extends ErrorAwareTreePathScanner<Void, Void> {
Expand Down Expand Up @@ -644,6 +650,11 @@ public Object[] getOpenInfo(ClasspathInfo cpInfo, ElementHandle<? extends Elemen
return ElementOpen.getOpenInfo(cpInfo, el, null, cancel);
}

@Override
public void fillInTreePositions(CompilationInfo info, Tree forTree, Object[] target) {
ElementOpen.fillInTreePositions(info, forTree, target);
}

@Override
public CompletableFuture<Object[]> getOpenInfoFuture(final ClasspathInfo cpInfo, final ElementHandle<? extends Element> el, String nameOpt, AtomicBoolean cancel, boolean acquire) {
return ElementOpen.getFutureOpenInfo(cpInfo, el, nameOpt, cancel, acquire);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
*/
package org.netbeans.modules.java.source.ui;

import com.sun.source.tree.Tree;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.lang.model.element.Element;
import org.netbeans.api.java.source.ClasspathInfo;
import org.netbeans.api.java.source.CompilationInfo;
import org.netbeans.api.java.source.ElementHandle;
import org.netbeans.api.java.source.ui.ElementOpen;

Expand All @@ -42,6 +44,7 @@ public static synchronized void setInstance(ElementOpenAccessor instance) {
}

public abstract Object[] getOpenInfo(final ClasspathInfo cpInfo, final ElementHandle<? extends Element> el, AtomicBoolean cancel);
public abstract void fillInTreePositions(CompilationInfo info, Tree forTree, Object[] target);

public abstract CompletableFuture<Object[]> getOpenInfoFuture(final ClasspathInfo cpInfo, final ElementHandle<? extends Element> el, String nameOpt, AtomicBoolean cancel, boolean acquire);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
package org.netbeans.modules.java.source.ui;

import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreePath;
import com.sun.source.util.TreePathScanner;
import java.io.IOException;
Expand All @@ -35,6 +37,7 @@
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.NestingKind;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
Expand All @@ -55,16 +58,17 @@
import org.netbeans.api.lsp.StructureElement;
import org.netbeans.spi.lsp.StructureProvider;
import org.openide.filesystems.FileObject;
import org.openide.util.NbBundle.Messages;

/**
*
* @author sdedic
*/
public class LspElementUtils {

public static StructureElement element2StructureElement(CompilationInfo info, Element el, ElementAcceptor childAcceptor,
public static StructureElement element2StructureElement(CompilationInfo info, Element el, TreePath elPath, ElementAcceptor childAcceptor,
boolean allowResources, boolean bypassOpen, FileObject parentFile) {
TreePath path = info.getTrees().getPath(el);
TreePath path = elPath != null ? elPath : info.getTrees().getPath(el);
if (!allowResources) {
if (path == null) {
return null;
Expand All @@ -80,10 +84,8 @@ public static StructureElement element2StructureElement(CompilationInfo info, El
FileObject f = null;
FileObject owner = null;
if (!bypassOpen) {
Object[] oi = setOffsets(info, el, builder);
if (oi != null) {
owner = f = (FileObject)oi[0];
}
FileObject file = setOffsets(info, el, path, builder);
owner = f = file;
} else {
f = null;
owner = parentFile;
Expand All @@ -100,15 +102,15 @@ public static StructureElement element2StructureElement(CompilationInfo info, El

if (childAcceptor != null) {
for (Element child : el.getEnclosedElements()) {
TreePath p = info.getTrees().getPath(child);
TreePath p = getChildPath(info, child, path);
if (!allowResources) {
if (p == null) {
continue;
}
}
TypeMirror m = child.asType();
if (childAcceptor.accept(child, m)) {
StructureElement jse = element2StructureElement(info, child, childAcceptor, allowResources, f == null, owner);
StructureElement jse = element2StructureElement(info, child, p, childAcceptor, allowResources, f == null, owner);
if (jse != null) {
builder.children(jse);
}
Expand All @@ -125,8 +127,25 @@ public static StructureElement element2StructureElement(CompilationInfo info, El
return builder.build();
}

private static TreePath getChildPath(CompilationInfo ci, Element child, TreePath parentPath) {
if (parentPath != null && child != null &&
TreeUtilities.CLASS_TREE_KINDS.contains(parentPath.getLeaf().getKind())) {
ClassTree ct = (ClassTree) parentPath.getLeaf();

for (Tree member : ct.getMembers()) {
TreePath memberPath = new TreePath(parentPath, member);

if (child.equals(ci.getTrees().getElement(memberPath))) {
return memberPath;
}
}
}

return ci.getTrees().getPath(child);
}

public static StructureElement element2StructureElement(CompilationInfo info, Element el, ElementAcceptor childAcceptor) {
return element2StructureElement(info, el, childAcceptor, false, false, null);
return element2StructureElement(info, el, null, childAcceptor, false, false, null);
}

static FileObject findOwnerResource(CompilationInfo info, Element el) {
Expand Down Expand Up @@ -166,7 +185,7 @@ static FileObject findOwnerResource(CompilationInfo info, Element el) {
}

public static StructureElement describeElement(CompilationInfo info, Element el, ElementAcceptor childAcceptor, boolean allowBinary) {
return element2StructureElement(info, el, childAcceptor, allowBinary, false, null);
return element2StructureElement(info, el, null, childAcceptor, allowBinary, false, null);
}

public static CompletableFuture<StructureElement> createStructureElement(CompilationInfo info, Element el, boolean resolveSources) {
Expand Down Expand Up @@ -199,6 +218,7 @@ private static CompletableFuture<StructureProvider.Builder> createStructureEleme
return setFutureOffsets(info, el, builder, cancel, acquire);
}

@Messages("LBL_AnonymousClass=<anonymous class based on {0}>")
private static String createName(CompilationInfo ci, Element original) {
switch (original.getKind()) {
case PACKAGE:
Expand All @@ -211,7 +231,13 @@ private static String createName(CompilationInfo ci, Element original) {
case RECORD:
TypeElement te = (TypeElement) original;
StringBuilder sb = new StringBuilder();
sb.append(te.getSimpleName());
if (te.getNestingKind() == NestingKind.ANONYMOUS) {
String name = te.getInterfaces().isEmpty() ? te.getSuperclass().toString()
: te.getInterfaces().get(0).toString();
sb.append(Bundle.LBL_AnonymousClass(name));
} else {
sb.append(te.getSimpleName());
}
List<? extends TypeParameterElement> typeParams = te.getTypeParameters();
if (typeParams != null && !typeParams.isEmpty()) {
sb.append("<"); // NOI18N
Expand Down Expand Up @@ -299,14 +325,6 @@ private static StructureProvider.Builder processOffsetInfo(Object[] info, Struct
if (info == null) {
return builder;
}
int selStart = (int)info[3];
if (selStart < 0) {
selStart = (int)info[1];
}
int selEnd = (int)info[4];
if (selEnd < 0) {
selEnd = (int)info[2];
}
TreePathHandle pathHandle = (TreePathHandle)info[6];
FileObject f = (FileObject)info[0];
boolean[] synthetic = new boolean[] { false };
Expand All @@ -330,9 +348,21 @@ private static StructureProvider.Builder processOffsetInfo(Object[] info, Struct
if (synthetic[0]) {
return null;
}
fillInPositions(info, builder);
return builder;
}

private static void fillInPositions(Object[] info, StructureProvider.Builder builder) {
int selStart = (int)info[3];
if (selStart < 0) {
selStart = (int)info[1];
}
int selEnd = (int)info[4];
if (selEnd < 0) {
selEnd = (int)info[2];
}
builder.expandedStartOffset((int)info[1]).expandedEndOffset((int)info[2]);
builder.selectionStartOffset(selStart).selectionEndOffset(selEnd);
return builder;
}

private static CompletableFuture<StructureProvider.Builder> setFutureOffsets(CompilationInfo ci, Element original,
Expand All @@ -354,30 +384,36 @@ private static CompletableFuture<StructureProvider.Builder> setFutureOffsets(Com
info -> processOffsetInfo(info, builder));
}

private static Object[] setOffsets(CompilationInfo ci, Element original, StructureProvider.Builder builder) {
private static FileObject setOffsets(CompilationInfo ci, Element original, TreePath originalPath, StructureProvider.Builder builder) {
if (originalPath != null && originalPath.getCompilationUnit() == ci.getCompilationUnit()) {
Object[] positions = new Object[] {null, -1, -1, -1, -1};
builder.file(ci.getFileObject());
if (ci.getTreeUtilities().isSynthetic(originalPath)) {
return null;
}
ElementOpenAccessor.getInstance().fillInTreePositions(ci, originalPath.getLeaf(), positions);
fillInPositions(positions, builder);
return ci.getFileObject();
}
ElementHandle<Element> h = ElementHandle.create(original);
Object[] openInfo = ElementOpenAccessor.getInstance().getOpenInfo(ci.getClasspathInfo(), h, new AtomicBoolean());
processOffsetInfo(openInfo, builder);
return openInfo;
return (FileObject) openInfo[0];
}

private static void getAnonymousInnerClasses(CompilationInfo info, TreePath path, StructureProvider.Builder builder, ElementAcceptor childAcceptor) {
new TreePathScanner<Void, Void>() {
@Override
public Void visitNewClass(NewClassTree node, Void p) {
if (node.getClassBody() != null) {
Element e = info.getTrees().getElement(new TreePath(getCurrentPath(), node.getClassBody()));
if (e != null) {
TreePath path = new TreePath(getCurrentPath(), node.getIdentifier());
TypeMirror m = info.getTrees().getTypeMirror(path);
Element te = info.getTrees().getElement(path);
if (te != null & childAcceptor.accept(te, m)) {
StructureElement jse = element2StructureElement(info, te, childAcceptor);
if (jse != null) {
builder.children(jse);
}
TreePath bodyPath = new TreePath(getCurrentPath(), node.getClassBody());
Element e = info.getTrees().getElement(bodyPath);
if (e != null && childAcceptor.accept(e, e.asType())) {
StructureElement jse = element2StructureElement(info, e, bodyPath, childAcceptor, false, false, null);
if (jse != null) {
builder.children(jse);
}
}
}
}
return null;
}
Expand All @@ -387,7 +423,7 @@ public Void visitClass(ClassTree node, Void p) {
Element e = info.getTrees().getElement(getCurrentPath());
TypeMirror m = info.getTrees().getTypeMirror(getCurrentPath());
if (e != null & childAcceptor.accept(e, m)) {
StructureElement jse = element2StructureElement(info, e, childAcceptor);
StructureElement jse = element2StructureElement(info, e, getCurrentPath(), childAcceptor, false, false, null);
if (jse != null) {
builder.children(jse);
}
Expand Down
Loading

0 comments on commit 4d6ce7c

Please sign in to comment.