Skip to content

Commit 93ca0a7

Browse files
committed
Improving inline values.
1 parent a72b087 commit 93ca0a7

File tree

7 files changed

+263
-163
lines changed

7 files changed

+263
-163
lines changed

ide/api.lsp/manifest.mf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Manifest-Version: 1.0
22
OpenIDE-Module: org.netbeans.api.lsp/1
33
OpenIDE-Module-Localizing-Bundle: org/netbeans/api/lsp/Bundle.properties
4-
OpenIDE-Module-Specification-Version: 1.32
4+
OpenIDE-Module-Specification-Version: 1.33
55
AutoUpdate-Show-In-Client: false

ide/api.lsp/src/org/netbeans/api/lsp/InlineValue.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
*/
1919
package org.netbeans.api.lsp;
2020

21+
/**
22+
* An expression whose value may be show inline while debugging.
23+
*
24+
* @since 1.33
25+
*/
2126
public final class InlineValue {
2227
private final Range range;
2328
private final String expression;
@@ -27,14 +32,26 @@ private InlineValue(Range range, String expression) {
2732
this.expression = expression;
2833
}
2934

35+
/**
36+
* {@return Range to which the inline value applies}
37+
*/
3038
public Range getRange() {
3139
return range;
3240
}
3341

34-
public java.lang.String getExpression() {
42+
/**
43+
* {@return The expression of that should be evaluated for the inline value.}
44+
*/
45+
public String getExpression() {
3546
return expression;
3647
}
3748

49+
/**
50+
* {@return a new instance of {@code InlineValue}, based on the provided information.}
51+
*
52+
* @param range range to which the inline value should apply
53+
* @param expression expression that should be evaluted
54+
*/
3855
public static InlineValue createInlineVariable(Range range, String expression) {
3956
return new InlineValue(range, expression);
4057
}

ide/api.lsp/src/org/netbeans/spi/lsp/InlineValuesProvider.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@
2424
import org.netbeans.api.lsp.InlineValue;
2525
import org.openide.filesystems.FileObject;
2626

27+
/**
28+
* Compute {@link InlineValue}s for the given file and offset.
29+
*/
2730
public interface InlineValuesProvider {
31+
32+
/**
33+
* Compute {@linkplain InlineValue}s for the given file and location.
34+
*
35+
* @param file file for which the inline values should be computed
36+
* @param currentExecutionPosition position for which the inline values should be computed
37+
* @return the computed inline values
38+
*/
2839
public CompletableFuture<List<? extends InlineValue>> inlineValues(@NonNull FileObject file, int currentExecutionPosition);
2940
}

java/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/models/InlineValueComputerImpl.java

Lines changed: 20 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,8 @@
1818
*/
1919
package org.netbeans.modules.debugger.jpda.ui.models;
2020

21-
import com.sun.source.tree.ClassTree;
22-
import com.sun.source.tree.IdentifierTree;
23-
import com.sun.source.tree.LambdaExpressionTree;
24-
import com.sun.source.tree.LineMap;
25-
import com.sun.source.tree.Tree;
26-
import static com.sun.source.tree.Tree.Kind.BLOCK;
27-
import static com.sun.source.tree.Tree.Kind.LAMBDA_EXPRESSION;
28-
import static com.sun.source.tree.Tree.Kind.METHOD;
29-
import com.sun.source.tree.VariableTree;
30-
import com.sun.source.util.TreePath;
3121
import java.beans.PropertyChangeEvent;
3222
import java.beans.PropertyChangeListener;
33-
import java.io.IOException;
3423
import java.net.MalformedURLException;
3524
import java.net.URI;
3625
import java.util.ArrayList;
@@ -41,15 +30,13 @@
4130
import java.util.List;
4231
import java.util.Map;
4332
import java.util.Objects;
44-
import java.util.concurrent.CompletableFuture;
4533
import java.util.concurrent.CountDownLatch;
4634
import java.util.concurrent.atomic.AtomicBoolean;
4735
import java.util.concurrent.atomic.AtomicReference;
4836
import java.util.function.Consumer;
37+
import java.util.logging.Level;
4938
import java.util.logging.Logger;
5039
import java.util.stream.Collectors;
51-
import javax.lang.model.element.Element;
52-
import javax.lang.model.element.ElementKind;
5340
import javax.swing.text.AttributeSet;
5441
import javax.swing.text.Document;
5542
import org.netbeans.api.debugger.DebuggerManagerAdapter;
@@ -65,14 +52,9 @@
6552
import org.netbeans.api.editor.settings.AttributesUtilities;
6653
import org.netbeans.api.java.source.CancellableTask;
6754
import org.netbeans.api.java.source.CompilationInfo;
68-
import org.netbeans.api.java.source.JavaSource;
6955
import org.netbeans.api.java.source.JavaSource.Phase;
7056
import org.netbeans.api.java.source.JavaSource.Priority;
7157
import org.netbeans.api.java.source.JavaSourceTaskFactory;
72-
import org.netbeans.api.java.source.TreeUtilities;
73-
import org.netbeans.api.java.source.support.CancellableTreePathScanner;
74-
import org.netbeans.api.lsp.InlineValue;
75-
import org.netbeans.api.lsp.Range;
7658
import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl;
7759
import org.netbeans.modules.debugger.jpda.expr.formatters.Formatters;
7860
import org.netbeans.modules.debugger.jpda.expr.formatters.FormattersLoopControl;
@@ -81,14 +63,16 @@
8163
import org.netbeans.modules.debugger.jpda.jdi.InvalidStackFrameExceptionWrapper;
8264
import org.netbeans.modules.debugger.jpda.jdi.ObjectCollectedExceptionWrapper;
8365
import org.netbeans.modules.debugger.jpda.jdi.VMDisconnectedExceptionWrapper;
66+
import org.netbeans.modules.debugger.jpda.ui.values.ComputeInlineValues;
67+
import org.netbeans.modules.debugger.jpda.ui.values.ComputeInlineValues.InlineVariable;
8468
import org.netbeans.modules.parsing.spi.TaskIndexingMode;
8569
import org.netbeans.spi.debugger.ContextProvider;
8670
import org.netbeans.spi.debugger.DebuggerServiceRegistration;
8771
import org.netbeans.spi.editor.highlighting.HighlightsLayer;
8872
import org.netbeans.spi.editor.highlighting.HighlightsLayerFactory;
73+
import org.netbeans.spi.editor.highlighting.HighlightsSequence;
8974
import org.netbeans.spi.editor.highlighting.ZOrder;
9075
import org.netbeans.spi.editor.highlighting.support.OffsetsBag;
91-
import org.netbeans.spi.lsp.InlineValuesProvider;
9276
import org.openide.cookies.EditorCookie;
9377
import org.openide.filesystems.FileObject;
9478
import org.openide.filesystems.URLMapper;
@@ -102,7 +86,8 @@
10286
@DebuggerServiceRegistration(path="netbeans-JPDASession/inlineValue", types=InlineValueComputer.class)
10387
public class InlineValueComputerImpl implements InlineValueComputer, PropertyChangeListener {
10488

105-
private static final RequestProcessor EVALUATOR = new RequestProcessor(InlineValueProviderImpl.class.getName(), 1, false, false);
89+
private static final Logger LOG = Logger.getLogger(InlineValueComputerImpl.class.getName());
90+
private static final RequestProcessor EVALUATOR = new RequestProcessor(InlineValueComputerImpl.class.getName(), 1, false, false);
10691
private static final String JAVA_STRATUM = "Java"; //XXX: this is probably already defined somewhere
10792
private final JPDADebuggerImpl debugger;
10893
private TaskDescription currentTask;
@@ -163,7 +148,6 @@ public void propertyChange(PropertyChangeEvent evt) {
163148
AtomicReference<Collection<InlineVariable>> values = new AtomicReference<>();
164149

165150
EVALUATOR.post(() -> {
166-
OffsetsBag currentDocumentBag = getHighlightsBag(newTask.frameDocument);
167151
OffsetsBag runningBag = new OffsetsBag(newTask.frameDocument);
168152

169153
Lookup.getDefault().lookup(ComputeInlineVariablesFactory.class).set(newTask.frameFile, newTask.frameLineNumber, variables -> {
@@ -199,8 +183,9 @@ public void propertyChange(PropertyChangeEvent evt) {
199183
try {
200184
return debugger.evaluate(expr);
201185
} catch (InvalidExpressionException ex) {
202-
Exceptions.printStackTrace(ex);
203-
return null; //TODO: avoid re-evaluation(!)
186+
//the variable may not exist
187+
LOG.log(Level.FINE, null, ex);
188+
return null;
204189
}
205190
});
206191
if (value != null) {
@@ -217,10 +202,7 @@ public void propertyChange(PropertyChangeEvent evt) {
217202

218203
runningBag.addHighlight(v.lineEnd, v.lineEnd + 1, attrs);
219204

220-
if (!newTask.isCancelled()) {
221-
//TODO: a slight race condition:
222-
currentDocumentBag.setHighlights(runningBag);
223-
}
205+
setHighlights(newTask, runningBag);
224206
}
225207
}
226208
});
@@ -305,6 +287,12 @@ private synchronized boolean setNewTask(TaskDescription newTask) {
305287
return false;
306288
}
307289

290+
private synchronized void setHighlights(TaskDescription task, OffsetsBag highlights) {
291+
if (!task.isCancelled()) {
292+
getHighlightsBag(currentTask.frameDocument).setHighlights(highlights);
293+
}
294+
}
295+
308296
@DebuggerServiceRegistration(types=LazyDebuggerManagerListener.class)
309297
public static final class Init extends DebuggerManagerAdapter {
310298
@Override
@@ -353,7 +341,7 @@ public void run(CompilationInfo info) throws Exception {
353341
target = currentTarget;
354342
}
355343

356-
Collection<InlineVariable> variables = computeVariables(info, line, 1, cancel);
344+
Collection<InlineVariable> variables = ComputeInlineValues.computeVariables(info, line, 1, cancel);
357345

358346
target.accept(variables);
359347
}
@@ -376,99 +364,6 @@ public synchronized void set(FileObject currentFile, int lineNumber, Consumer<Co
376364
}
377365
}
378366

379-
static Collection<InlineVariable> computeVariables(CompilationInfo info, int stackLine, int stackCol, AtomicBoolean cancel) {
380-
Collection<InlineVariable> result = new ArrayList<>();
381-
int donePos = (int) info.getCompilationUnit().getLineMap().getPosition(stackLine, stackCol);
382-
int upcomingPos = (int) info.getCompilationUnit().getLineMap().getStartPosition(stackLine + 1);
383-
TreePath relevantPoint = info.getTreeUtilities().pathFor(donePos);
384-
OUTER: while (relevantPoint != null) {
385-
Tree leaf = relevantPoint.getLeaf();
386-
switch (leaf.getKind()) {
387-
case METHOD: case LAMBDA_EXPRESSION: break OUTER;
388-
case BLOCK:
389-
if (relevantPoint.getParentPath() != null && TreeUtilities.CLASS_TREE_KINDS.contains(relevantPoint.getParentPath().getLeaf().getKind())) {
390-
break OUTER;
391-
}
392-
}
393-
relevantPoint = relevantPoint.getParentPath();
394-
}
395-
LineMap lm = info.getCompilationUnit().getLineMap();
396-
new CancellableTreePathScanner<Void, Void>(cancel) {
397-
@Override
398-
public Void visitVariable(VariableTree node, Void p) {
399-
int end = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), node);
400-
if (end < donePos) {
401-
int[] span = info.getTreeUtilities().findNameSpan(node);
402-
403-
if (span != null) {
404-
int lineEnd = (int) (lm.getStartPosition(lm.getLineNumber(span[1]) + 1) - 1);
405-
406-
result.add(new InlineVariable(span[0], span[1], lineEnd, node.getName().toString()));
407-
}
408-
}
409-
return super.visitVariable(node, p);
410-
}
411-
412-
@Override
413-
public Void visitIdentifier(IdentifierTree node, Void p) {
414-
Element el = info.getTrees().getElement(getCurrentPath());
415-
416-
if (el != null && el.getKind().isVariable() && el.getKind() != ElementKind.ENUM_CONSTANT) {
417-
int start = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), node);
418-
int end = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), node);
419-
420-
if (start != (-1) && end != (-1)) {
421-
int lineEnd = (int) (lm.getStartPosition(lm.getLineNumber(end) + 1) - 1);
422-
423-
result.add(new InlineVariable(start, end, lineEnd, node.getName().toString()));
424-
}
425-
}
426-
427-
return super.visitIdentifier(node, p);
428-
}
429-
430-
@Override
431-
public Void visitClass(ClassTree node, Void p) {
432-
return null;
433-
}
434-
435-
@Override
436-
public Void visitLambdaExpression(LambdaExpressionTree node, Void p) {
437-
return null;
438-
}
439-
440-
@Override
441-
public Void scan(Tree tree, Void p) {
442-
if (tree != null) {
443-
int start = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), tree);
444-
445-
if (start > upcomingPos) {
446-
return null;
447-
}
448-
}
449-
return super.scan(tree, p);
450-
}
451-
452-
}.scan(relevantPoint, null);
453-
454-
return result;
455-
}
456-
457-
public static final class InlineVariable {
458-
public final int start;
459-
public final int end;
460-
public final int lineEnd;
461-
public final String expression;
462-
463-
public InlineVariable(int start, int end, int lineEnd, String expression) {
464-
this.start = start;
465-
this.end = end;
466-
this.lineEnd = lineEnd;
467-
this.expression = expression;
468-
}
469-
470-
}
471-
472367
private static final class TaskDescription {
473368
public final FileObject frameFile;
474369
public final int frameLineNumber;
@@ -546,48 +441,18 @@ public static HighlightsLayerFactory createHighlightsLayerFactory() {
546441
@Override
547442
public HighlightsLayer[] createLayers(HighlightsLayerFactory.Context context) {
548443
return new HighlightsLayer[] {
549-
HighlightsLayer.create(InlineValueProviderImpl.class.getName(), ZOrder.SYNTAX_RACK.forPosition(1400), false, getHighlightsBag(context.getDocument()))
444+
HighlightsLayer.create(InlineValueComputerImpl.class.getName(), ZOrder.SYNTAX_RACK.forPosition(1400), false, getHighlightsBag(context.getDocument()))
550445
};
551446
}
552447
};
553448
}
554449

555450
private static OffsetsBag getHighlightsBag(Document doc) {
556-
OffsetsBag bag = (OffsetsBag) doc.getProperty(InlineValueProviderImpl.class);
451+
OffsetsBag bag = (OffsetsBag) doc.getProperty(InlineValueComputerImpl.class);
557452
if (bag == null) {
558-
doc.putProperty(InlineValueProviderImpl.class, bag = new OffsetsBag(doc, true));
453+
doc.putProperty(InlineValueComputerImpl.class, bag = new OffsetsBag(doc, true));
559454
}
560455
return bag;
561456
}
562457

563-
@MimeRegistration(mimeType="text/x-java", service=InlineValuesProvider.class)
564-
public static final class InlineValueProviderImpl implements InlineValuesProvider {
565-
566-
@Override
567-
public CompletableFuture<List<? extends InlineValue>> inlineValues(FileObject file, int currentExecutionPosition) {
568-
//TODO: proper cancellability
569-
JavaSource js = JavaSource.forFileObject(file);
570-
CompletableFuture<List<? extends InlineValue>> result = new CompletableFuture<>();
571-
List<InlineValue> resultValues = new ArrayList<>();
572-
if (js != null) {
573-
try {
574-
js.runUserActionTask(cc -> {
575-
cc.toPhase(JavaSource.Phase.RESOLVED);
576-
int stackLine = (int) cc.getCompilationUnit().getLineMap().getLineNumber(currentExecutionPosition);
577-
int stackCol = (int) cc.getCompilationUnit().getLineMap().getColumnNumber(currentExecutionPosition);
578-
579-
for (InlineVariable var : computeVariables(cc, stackLine, stackCol, new AtomicBoolean())) {
580-
resultValues.add(InlineValue.createInlineVariable(new Range(var.start, var.end), var.expression));
581-
}
582-
}, true);
583-
} catch (IOException ex) {
584-
result.completeExceptionally(ex);
585-
return result;
586-
}
587-
}
588-
result.complete(resultValues);
589-
return result;
590-
}
591-
592-
}
593458
}

0 commit comments

Comments
 (0)