mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-168070 Allow to use expression as a Capture key
This commit is contained in:
+1
-2
@@ -243,8 +243,7 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp
|
||||
if (myReference.equals(thisRef.referenceType()) && data != null) {
|
||||
thisRef.disableCollection();
|
||||
myTrackedObjects.add(thisRef);
|
||||
final List<StackFrameItem> frame = StackFrameItem.createFrames(suspendContext.getThread(), suspendContext, false);
|
||||
data.getTrackedStacks().addStack(thisRef, frame);
|
||||
data.getTrackedStacks().addStack(thisRef, StackFrameItem.createFrames(suspendContext, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,10 +70,8 @@ public class StackFrameItem {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<StackFrameItem> createFrames(@Nullable ThreadReferenceProxyImpl threadReferenceProxy,
|
||||
@NotNull SuspendContextImpl suspendContext,
|
||||
boolean withVars)
|
||||
throws EvaluateException {
|
||||
public static List<StackFrameItem> createFrames(@NotNull SuspendContextImpl suspendContext, boolean withVars) throws EvaluateException {
|
||||
ThreadReferenceProxyImpl threadReferenceProxy = suspendContext.getThread();
|
||||
if (threadReferenceProxy != null) {
|
||||
List<StackFrameItem> res = new ArrayList<>();
|
||||
for (StackFrameProxyImpl frame : threadReferenceProxy.frames()) {
|
||||
|
||||
@@ -204,7 +204,7 @@ public class CaptureConfigurable implements SearchableConfigurable {
|
||||
public static final int INSERT_KEY_EXPR = 6;
|
||||
|
||||
static final String[] COLUMN_NAMES =
|
||||
new String[]{"", "Class name", "Method name", "Param index", "Insert class name", "Insert method name", "Insert key expression"};
|
||||
new String[]{"", "Class name", "Method name", "Key expression", "Insert class name", "Insert method name", "Insert key expression"};
|
||||
List<CapturePoint> myCapturePoints = DebuggerSettings.getInstance().cloneCapturePoints();
|
||||
|
||||
public String getColumnName(int column) {
|
||||
@@ -229,7 +229,7 @@ public class CaptureConfigurable implements SearchableConfigurable {
|
||||
case METHOD_COLUMN:
|
||||
return point.myMethodName;
|
||||
case PARAM_COLUMN:
|
||||
return point.myParamNo;
|
||||
return point.myCaptureKeyExpression;
|
||||
case INSERT_CLASS_COLUMN:
|
||||
return point.myInsertClassName;
|
||||
case INSERT_METHOD_COLUMN:
|
||||
@@ -257,7 +257,7 @@ public class CaptureConfigurable implements SearchableConfigurable {
|
||||
point.myMethodName = (String)value;
|
||||
break;
|
||||
case PARAM_COLUMN:
|
||||
point.myParamNo = (int)value;
|
||||
point.myCaptureKeyExpression = (String)value;
|
||||
break;
|
||||
case INSERT_CLASS_COLUMN:
|
||||
point.myInsertClassName = (String)value;
|
||||
@@ -276,8 +276,6 @@ public class CaptureConfigurable implements SearchableConfigurable {
|
||||
switch (columnIndex) {
|
||||
case ENABLED_COLUMN:
|
||||
return Boolean.class;
|
||||
case PARAM_COLUMN:
|
||||
return Integer.class;
|
||||
}
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ public class CapturePoint implements Cloneable {
|
||||
@Attribute("method-name")
|
||||
public String myMethodName;
|
||||
|
||||
@Attribute("param-idx")
|
||||
public int myParamNo = 0;
|
||||
@Attribute("capture-key-expression")
|
||||
public String myCaptureKeyExpression;
|
||||
|
||||
@Attribute("insert-class-name")
|
||||
public String myInsertClassName;
|
||||
@@ -49,15 +49,19 @@ public class CapturePoint implements Cloneable {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
CapturePoint point = (CapturePoint)o;
|
||||
CapturePoint that = (CapturePoint)o;
|
||||
|
||||
if (myEnabled != point.myEnabled) return false;
|
||||
if (myParamNo != point.myParamNo) return false;
|
||||
if (myClassName != null ? !myClassName.equals(point.myClassName) : point.myClassName != null) return false;
|
||||
if (myMethodName != null ? !myMethodName.equals(point.myMethodName) : point.myMethodName != null) return false;
|
||||
if (myInsertClassName != null ? !myInsertClassName.equals(point.myInsertClassName) : point.myInsertClassName != null) return false;
|
||||
if (myInsertMethodName != null ? !myInsertMethodName.equals(point.myInsertMethodName) : point.myInsertMethodName != null) return false;
|
||||
if (myInsertKeyExpression != null ? !myInsertKeyExpression.equals(point.myInsertKeyExpression) : point.myInsertKeyExpression != null) {
|
||||
if (myEnabled != that.myEnabled) return false;
|
||||
if (myClassName != null ? !myClassName.equals(that.myClassName) : that.myClassName != null) return false;
|
||||
if (myMethodName != null ? !myMethodName.equals(that.myMethodName) : that.myMethodName != null) return false;
|
||||
if (myCaptureKeyExpression != null
|
||||
? !myCaptureKeyExpression.equals(that.myCaptureKeyExpression)
|
||||
: that.myCaptureKeyExpression != null) {
|
||||
return false;
|
||||
}
|
||||
if (myInsertClassName != null ? !myInsertClassName.equals(that.myInsertClassName) : that.myInsertClassName != null) return false;
|
||||
if (myInsertMethodName != null ? !myInsertMethodName.equals(that.myInsertMethodName) : that.myInsertMethodName != null) return false;
|
||||
if (myInsertKeyExpression != null ? !myInsertKeyExpression.equals(that.myInsertKeyExpression) : that.myInsertKeyExpression != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -69,7 +73,7 @@ public class CapturePoint implements Cloneable {
|
||||
int result = (myEnabled ? 1 : 0);
|
||||
result = 31 * result + (myClassName != null ? myClassName.hashCode() : 0);
|
||||
result = 31 * result + (myMethodName != null ? myMethodName.hashCode() : 0);
|
||||
result = 31 * result + myParamNo;
|
||||
result = 31 * result + (myCaptureKeyExpression != null ? myCaptureKeyExpression.hashCode() : 0);
|
||||
result = 31 * result + (myInsertClassName != null ? myInsertClassName.hashCode() : 0);
|
||||
result = 31 * result + (myInsertMethodName != null ? myInsertMethodName.hashCode() : 0);
|
||||
result = 31 * result + (myInsertKeyExpression != null ? myInsertKeyExpression.hashCode() : 0);
|
||||
|
||||
+57
-45
@@ -15,33 +15,31 @@
|
||||
*/
|
||||
package com.intellij.debugger.ui.breakpoints;
|
||||
|
||||
import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.ContextUtil;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.CodeFragmentKind;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
|
||||
import com.intellij.debugger.engine.evaluation.*;
|
||||
import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
|
||||
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
|
||||
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem;
|
||||
import com.intellij.debugger.settings.CapturePoint;
|
||||
import com.intellij.debugger.settings.DebuggerSettings;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.NullableLazyValue;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.sun.jdi.Location;
|
||||
import com.sun.jdi.Method;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.Value;
|
||||
import com.sun.jdi.*;
|
||||
import com.sun.jdi.event.LocatableEvent;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -63,10 +61,11 @@ public class StackCapturingLineBreakpoint extends WildcardMethodBreakpoint {
|
||||
private final CapturePoint myCapturePoint;
|
||||
private final String mySignature;
|
||||
|
||||
private final NullableLazyValue<ExpressionEvaluator> myEvaluator;
|
||||
private final MyEvaluator myCaptureEvaluator;
|
||||
private final MyEvaluator myInsertEvaluator;
|
||||
|
||||
public static final Key<List<StackCapturingLineBreakpoint>> CAPTURE_BREAKPOINTS = Key.create("CAPTURE_BREAKPOINTS");
|
||||
public static final Key<Map<ObjectReference, List<StackFrameItem>>> CAPTURED_STACKS = Key.create("CAPTURED_STACKS");
|
||||
private static final Key<Map<Object, List<StackFrameItem>>> CAPTURED_STACKS = Key.create("CAPTURED_STACKS");
|
||||
private static final int MAX_STORED_STACKS = 1000;
|
||||
public static final int MAX_STACK_LENGTH = 500;
|
||||
|
||||
@@ -81,16 +80,8 @@ public class StackCapturingLineBreakpoint extends WildcardMethodBreakpoint {
|
||||
myProperties.myClassPattern = myCapturePoint.myClassName;
|
||||
myProperties.myMethodName = myCapturePoint.myMethodName;
|
||||
|
||||
myEvaluator = NullableLazyValue.createValue(() -> ReadAction.compute(() -> {
|
||||
try {
|
||||
return EvaluatorBuilderImpl.build(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, myCapturePoint.myInsertKeyExpression),
|
||||
null, null, project);
|
||||
}
|
||||
catch (EvaluateException e) {
|
||||
LOG.warn(e);
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
myCaptureEvaluator = new MyEvaluator(myCapturePoint.myCaptureKeyExpression);
|
||||
myInsertEvaluator = new MyEvaluator(myCapturePoint.myInsertKeyExpression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -112,23 +103,24 @@ public class StackCapturingLineBreakpoint extends WildcardMethodBreakpoint {
|
||||
StackFrameProxyImpl frameProxy = suspendContext.getFrameProxy();
|
||||
if (frameProxy != null) {
|
||||
DebugProcessImpl process = suspendContext.getDebugProcess();
|
||||
Map<ObjectReference, List<StackFrameItem>> stacks = process.getUserData(CAPTURED_STACKS);
|
||||
Map<Object, List<StackFrameItem>> stacks = process.getUserData(CAPTURED_STACKS);
|
||||
if (stacks == null) {
|
||||
stacks = new CapturedStacksMap();
|
||||
process.putUserData(CAPTURED_STACKS, Collections.synchronizedMap(stacks));
|
||||
}
|
||||
Value key = ContainerUtil.getOrElse(frameProxy.getArgumentValues(), myCapturePoint.myParamNo, null);
|
||||
Value key = myCaptureEvaluator.evaluate(new EvaluationContextImpl(suspendContext, frameProxy, frameProxy.thisObject()));
|
||||
if (key instanceof ObjectReference) {
|
||||
List<StackFrameItem> frames = StackFrameItem.createFrames(suspendContext.getThread(), suspendContext, true);
|
||||
List<StackFrameItem> frames = StackFrameItem.createFrames(suspendContext, true);
|
||||
if (frames.size() > MAX_STACK_LENGTH) {
|
||||
frames = frames.subList(0, MAX_STACK_LENGTH);
|
||||
}
|
||||
stacks.put((ObjectReference)key, frames);
|
||||
stacks.put(getKey((ObjectReference)key), frames);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (EvaluateException ignored) {
|
||||
catch (EvaluateException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -137,7 +129,7 @@ public class StackCapturingLineBreakpoint extends WildcardMethodBreakpoint {
|
||||
protected void fireBreakpointChanged() {
|
||||
}
|
||||
|
||||
private static class CapturedStacksMap extends LinkedHashMap<ObjectReference, List<StackFrameItem>> {
|
||||
private static class CapturedStacksMap extends LinkedHashMap<Object, List<StackFrameItem>> {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry eldest) {
|
||||
return size() > MAX_STORED_STACKS;
|
||||
@@ -186,7 +178,7 @@ public class StackCapturingLineBreakpoint extends WildcardMethodBreakpoint {
|
||||
public static List<StackFrameItem> getRelatedStack(@Nullable StackFrameProxyImpl frame, @NotNull SuspendContextImpl suspendContext) {
|
||||
if (frame != null) {
|
||||
DebugProcessImpl debugProcess = suspendContext.getDebugProcess();
|
||||
Map<ObjectReference, List<StackFrameItem>> capturedStacks = debugProcess.getUserData(CAPTURED_STACKS);
|
||||
Map<Object, List<StackFrameItem>> capturedStacks = debugProcess.getUserData(CAPTURED_STACKS);
|
||||
if (ContainerUtil.isEmpty(capturedStacks)) {
|
||||
return null;
|
||||
}
|
||||
@@ -198,33 +190,25 @@ public class StackCapturingLineBreakpoint extends WildcardMethodBreakpoint {
|
||||
Location location = frame.location();
|
||||
String className = location.declaringType().name();
|
||||
String methodName = location.method().name();
|
||||
List<Value> argumentValues = null;
|
||||
|
||||
for (StackCapturingLineBreakpoint b : captureBreakpoints) {
|
||||
String insertClassName = b.myCapturePoint.myInsertClassName;
|
||||
if ((StringUtil.isEmpty(insertClassName) || StringUtil.equals(insertClassName, className)) &&
|
||||
StringUtil.equals(b.myCapturePoint.myInsertMethodName, methodName)) {
|
||||
if (argumentValues == null) {
|
||||
argumentValues = frame.getArgumentValues();
|
||||
}
|
||||
|
||||
try {
|
||||
ExpressionEvaluator evaluator = b.myEvaluator.getValue();
|
||||
if (evaluator != null) {
|
||||
EvaluationContextImpl evaluationContext = new EvaluationContextImpl(suspendContext, frame, frame.thisObject());
|
||||
Value key = evaluator.evaluate(evaluationContext);
|
||||
|
||||
if (key instanceof ObjectReference) {
|
||||
return capturedStacks.get(key);
|
||||
}
|
||||
Value key = b.myInsertEvaluator.evaluate(new EvaluationContextImpl(suspendContext, frame, frame.thisObject()));
|
||||
if (key instanceof ObjectReference) {
|
||||
return capturedStacks.get(getKey((ObjectReference)key));
|
||||
}
|
||||
}
|
||||
catch (EvaluateException ignore) {
|
||||
catch (EvaluateException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (EvaluateException ignore) {
|
||||
catch (EvaluateException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -233,11 +217,39 @@ public class StackCapturingLineBreakpoint extends WildcardMethodBreakpoint {
|
||||
@Nullable
|
||||
public static List<StackFrameItem> getRelatedStack(@Nullable ObjectReference key, @Nullable DebugProcessImpl process) {
|
||||
if (process != null && key != null) {
|
||||
Map<ObjectReference, List<StackFrameItem>> data = process.getUserData(CAPTURED_STACKS);
|
||||
Map<Object, List<StackFrameItem>> data = process.getUserData(CAPTURED_STACKS);
|
||||
if (data != null) {
|
||||
return data.get(key);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Object getKey(ObjectReference reference) {
|
||||
return reference instanceof StringReference ? ((StringReference)reference).value() : reference;
|
||||
}
|
||||
|
||||
private static class MyEvaluator {
|
||||
private final String myExpression;
|
||||
ExpressionEvaluator myEvaluator;
|
||||
|
||||
public MyEvaluator(String expression) {
|
||||
myExpression = expression;
|
||||
}
|
||||
|
||||
Value evaluate(final EvaluationContext context) throws EvaluateException {
|
||||
if (myEvaluator == null) {
|
||||
myEvaluator = ApplicationManager.getApplication().runReadAction(
|
||||
(ThrowableComputable<ExpressionEvaluator, EvaluateException>)() -> {
|
||||
SourcePosition sourcePosition = ContextUtil.getSourcePosition(context);
|
||||
PsiElement contextElement = ContextUtil.getContextElement(sourcePosition);
|
||||
return EvaluatorBuilderImpl.build(
|
||||
new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, myExpression), contextElement, sourcePosition, context.getProject());
|
||||
});
|
||||
}
|
||||
Value value = myEvaluator.evaluate(context);
|
||||
DebuggerUtilsEx.keep(value, context);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user