Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing LspElementUtils with anonymous classes extending an enclosing class, and speeding up the StructureElement computation. #7707

Merged
merged 1 commit into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading