mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
IDEA-162947 Add ability to use lambda expressions in breakpoint conditions
- support log expressions as well
This commit is contained in:
@@ -25,12 +25,14 @@ import com.intellij.debugger.engine.*;
|
||||
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.evaluation.expression.UnsupportedExpressionException;
|
||||
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
|
||||
import com.intellij.debugger.requests.ClassPrepareRequestor;
|
||||
import com.intellij.debugger.settings.DebuggerSettings;
|
||||
import com.intellij.debugger.ui.impl.watch.EvaluationDescriptor;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
@@ -38,6 +40,7 @@ import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.JDOMExternalizerUtil;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiCodeFragment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.ui.AppUIUtil;
|
||||
import com.intellij.ui.classFilter.ClassFilter;
|
||||
@@ -63,6 +66,7 @@ import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperti
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class Breakpoint<P extends JavaBreakpointProperties> implements FilteredRequestor, ClassPrepareRequestor {
|
||||
public static final Key<Breakpoint> DATA_KEY = Key.create("JavaBreakpoint");
|
||||
@@ -264,8 +268,8 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
|
||||
try {
|
||||
SourcePosition position = ContextUtil.getSourcePosition(context);
|
||||
PsiElement element = ContextUtil.getContextElement(context, position);
|
||||
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject,
|
||||
() -> EvaluatorBuilderImpl.build(expressionToEvaluate, element, position, myProject));
|
||||
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, () ->
|
||||
createExpressionEvaluator(myProject, context, element, position, expressionToEvaluate, this::createLogMessageCodeFragment));
|
||||
Value eval = evaluator.evaluate(context);
|
||||
buf.append(eval instanceof VoidValue ? "void" : DebuggerUtils.getValueAsString(context, eval));
|
||||
}
|
||||
@@ -348,7 +352,8 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
|
||||
if (contextPsiElement == null) {
|
||||
contextPsiElement = getEvaluationElement(); // as a last resort
|
||||
}
|
||||
return EvaluatorBuilderImpl.build(getCondition(), contextPsiElement, contextSourcePosition, project);
|
||||
return createExpressionEvaluator(project, context, contextPsiElement, contextSourcePosition, getCondition(),
|
||||
this::createConditionCodeFragment);
|
||||
});
|
||||
return DebuggerUtilsEx.evaluateBoolean(evaluator, context);
|
||||
}
|
||||
@@ -362,6 +367,37 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
|
||||
}
|
||||
}
|
||||
|
||||
private static ExpressionEvaluator createExpressionEvaluator(Project project,
|
||||
EvaluationContextImpl context,
|
||||
PsiElement contextPsiElement,
|
||||
SourcePosition contextSourcePosition,
|
||||
TextWithImports text,
|
||||
Function<PsiElement, PsiCodeFragment> fragmentFactory)
|
||||
throws EvaluateException {
|
||||
try {
|
||||
return EvaluatorBuilderImpl.build(text, contextPsiElement, contextSourcePosition, project);
|
||||
}
|
||||
catch (UnsupportedExpressionException ex) {
|
||||
ExpressionEvaluator eval = EvaluationDescriptor.createCompilingEvaluator(context, contextPsiElement, fragmentFactory);
|
||||
if (eval != null) {
|
||||
return eval;
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
private PsiCodeFragment createConditionCodeFragment(PsiElement context) {
|
||||
return createCodeFragment(getProject(), getCondition(), context);
|
||||
}
|
||||
|
||||
private PsiCodeFragment createLogMessageCodeFragment(PsiElement context) {
|
||||
return createCodeFragment(getProject(), getLogMessage(), context);
|
||||
}
|
||||
|
||||
private static PsiCodeFragment createCodeFragment(Project project, TextWithImports text, PsiElement context) {
|
||||
return DebuggerUtilsEx.findAppropriateCodeFragmentFactory(text, context).createCodeFragment(text, context, project);
|
||||
}
|
||||
|
||||
protected String calculateEventClass(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException {
|
||||
return event.location().declaringType().name();
|
||||
}
|
||||
|
||||
+43
-33
@@ -30,7 +30,9 @@ import com.intellij.debugger.engine.evaluation.expression.UnsupportedExpressionE
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.refactoring.extractMethod.PrepareFailedException;
|
||||
@@ -40,10 +42,12 @@ import com.sun.jdi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @author lex
|
||||
*/
|
||||
public abstract class EvaluationDescriptor extends ValueDescriptorImpl{
|
||||
public abstract class EvaluationDescriptor extends ValueDescriptorImpl {
|
||||
private Modifier myModifier;
|
||||
protected TextWithImports myText;
|
||||
|
||||
@@ -58,7 +62,7 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl{
|
||||
myText = text;
|
||||
}
|
||||
|
||||
protected abstract EvaluationContextImpl getEvaluationContext (EvaluationContextImpl evaluationContext);
|
||||
protected abstract EvaluationContextImpl getEvaluationContext(EvaluationContextImpl evaluationContext);
|
||||
|
||||
protected abstract PsiCodeFragment getEvaluationCode(StackFrameContext context) throws EvaluateException;
|
||||
|
||||
@@ -73,35 +77,15 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl{
|
||||
SourcePosition position = ContextUtil.getSourcePosition(evaluationContext);
|
||||
PsiElement psiContext = ContextUtil.getContextElement(evaluationContext, position);
|
||||
|
||||
ExpressionEvaluator evaluator = null;
|
||||
ExpressionEvaluator evaluator;
|
||||
try {
|
||||
evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, new EvaluatingComputable<ExpressionEvaluator>() {
|
||||
public ExpressionEvaluator compute() throws EvaluateException {
|
||||
return DebuggerUtilsEx.findAppropriateCodeFragmentFactory(getEvaluationText(), psiContext).getEvaluatorBuilder().
|
||||
build(getEvaluationCode(thisEvaluationContext), position);
|
||||
}
|
||||
});
|
||||
evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, () ->
|
||||
DebuggerUtilsEx.findAppropriateCodeFragmentFactory(getEvaluationText(), psiContext)
|
||||
.getEvaluatorBuilder()
|
||||
.build(getEvaluationCode(thisEvaluationContext), position));
|
||||
}
|
||||
catch (UnsupportedExpressionException ex) {
|
||||
if (Registry.is("debugger.compiling.evaluator") && psiContext != null) {
|
||||
evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, new EvaluatingComputable<ExpressionEvaluator>() {
|
||||
public ExpressionEvaluator compute() throws EvaluateException {
|
||||
PsiFile psiFile = psiContext.getContainingFile();
|
||||
PsiCodeFragment fragment = createCodeFragment(psiContext);
|
||||
try {
|
||||
ExtractLightMethodObjectHandler.ExtractedData data = ExtractLightMethodObjectHandler.extractLightMethodObject(myProject,
|
||||
psiFile, fragment, CompilingEvaluator.getGeneratedClassName());
|
||||
if (data != null) {
|
||||
return new CompilingEvaluatorImpl(evaluationContext, psiContext, data);
|
||||
}
|
||||
}
|
||||
catch (PrepareFailedException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
evaluator = createCompilingEvaluator(evaluationContext, psiContext, this::createCodeFragment);
|
||||
if (evaluator == null) {
|
||||
throw ex;
|
||||
}
|
||||
@@ -131,9 +115,35 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl{
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ExpressionEvaluator createCompilingEvaluator(EvaluationContextImpl evaluationContext,
|
||||
@Nullable PsiElement psiContext,
|
||||
Function<PsiElement, PsiCodeFragment> fragmentFactory)
|
||||
throws EvaluateException {
|
||||
if (Registry.is("debugger.compiling.evaluator") && psiContext != null) {
|
||||
return ApplicationManager.getApplication().runReadAction((ThrowableComputable<ExpressionEvaluator, EvaluateException>)() -> {
|
||||
try {
|
||||
ExtractLightMethodObjectHandler.ExtractedData data = ExtractLightMethodObjectHandler.extractLightMethodObject(
|
||||
evaluationContext.getProject(),
|
||||
psiContext.getContainingFile(),
|
||||
fragmentFactory.apply(psiContext),
|
||||
CompilingEvaluator.getGeneratedClassName());
|
||||
if (data != null) {
|
||||
return new CompilingEvaluatorImpl(evaluationContext, psiContext, data);
|
||||
}
|
||||
}
|
||||
catch (PrepareFailedException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException {
|
||||
PsiElement evaluationCode = getEvaluationCode(context);
|
||||
if(evaluationCode instanceof PsiExpressionCodeFragment) {
|
||||
if (evaluationCode instanceof PsiExpressionCodeFragment) {
|
||||
return ((PsiExpressionCodeFragment)evaluationCode).getExpression();
|
||||
}
|
||||
else {
|
||||
@@ -171,10 +181,10 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl{
|
||||
}
|
||||
|
||||
public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws InvocationException,
|
||||
ClassNotLoadedException,
|
||||
IncompatibleThreadStateException,
|
||||
InvalidTypeException,
|
||||
EvaluateException {
|
||||
ClassNotLoadedException,
|
||||
IncompatibleThreadStateException,
|
||||
InvalidTypeException,
|
||||
EvaluateException {
|
||||
return evaluationContext.getDebugProcess().loadClass(evaluationContext, className,
|
||||
evaluationContext.getClassLoader());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user