summaryrefslogtreecommitdiff
path: root/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java')
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java385
1 files changed, 350 insertions, 35 deletions
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java
index 1b370ca47ded..bbbcf8ef1265 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java
@@ -30,45 +30,62 @@ import com.intellij.debugger.engine.requests.RequestManagerImpl;
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.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizerUtil;
import com.intellij.openapi.util.Key;
-import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
import com.intellij.ui.AppUIUtil;
+import com.intellij.ui.classFilter.ClassFilter;
import com.intellij.util.StringBuilderSpinAllocator;
-import com.sun.jdi.ObjectReference;
-import com.sun.jdi.ReferenceType;
-import com.sun.jdi.Value;
-import com.sun.jdi.VoidValue;
+import com.intellij.xdebugger.breakpoints.SuspendPolicy;
+import com.intellij.xdebugger.breakpoints.XBreakpoint;
+import com.intellij.xdebugger.breakpoints.XLineBreakpoint;
+import com.sun.jdi.*;
import com.sun.jdi.event.LocatableEvent;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties;
import javax.swing.*;
import java.util.List;
-public abstract class Breakpoint extends FilteredRequestor implements ClassPrepareRequestor {
- public boolean ENABLED = true;
- public boolean LOG_ENABLED = false;
- public boolean LOG_EXPRESSION_ENABLED = false;
- public boolean REMOVE_AFTER_HIT = false;
- private TextWithImports myLogMessage; // an expression to be evaluated and printed
+public abstract class Breakpoint<P extends JavaBreakpointProperties> implements FilteredRequestor, ClassPrepareRequestor {
+ final XBreakpoint<P> myXBreakpoint;
+ protected final Project myProject;
+
+ //private boolean ENABLED = true;
+ //private boolean LOG_ENABLED = false;
+ //private boolean LOG_EXPRESSION_ENABLED = false;
+ //private boolean REMOVE_AFTER_HIT = false;
+ //private TextWithImports myLogMessage; // an expression to be evaluated and printed
@NonNls private static final String LOG_MESSAGE_OPTION_NAME = "LOG_MESSAGE";
public static final Breakpoint[] EMPTY_ARRAY = new Breakpoint[0];
protected boolean myCachedVerifiedState = false;
+ //private TextWithImportsImpl myLogMessage;
- protected Breakpoint(@NotNull Project project) {
- super(project);
- myLogMessage = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, "");
+ protected Breakpoint(@NotNull Project project, XBreakpoint<P> xBreakpoint) {
+ //super(project);
+ myProject = project;
+ myXBreakpoint = xBreakpoint;
+ //myLogMessage = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, "");
//noinspection AbstractMethodCallInConstructor
- final BreakpointDefaults defaults = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().getBreakpointDefaults(getCategory());
- SUSPEND_POLICY = defaults.getSuspendPolicy();
- CONDITION_ENABLED = defaults.isConditionEnabled();
+ //final BreakpointDefaults defaults = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().getBreakpointDefaults(getCategory());
+ //SUSPEND_POLICY = defaults.getSuspendPolicy();
+ //CONDITION_ENABLED = defaults.isConditionEnabled();
+ }
+
+ public Project getProject() {
+ return myProject;
+ }
+
+ protected P getProperties() {
+ return myXBreakpoint.getProperties();
}
public abstract PsiClass getPsiClass();
@@ -100,6 +117,16 @@ public abstract class Breakpoint extends FilteredRequestor implements ClassPrepa
myCachedVerifiedState = isVerified;
}
+ public boolean isRemoveAfterHit() {
+ return myXBreakpoint instanceof XLineBreakpoint && ((XLineBreakpoint)myXBreakpoint).isTemporary();
+ }
+
+ public void setRemoveAfterHit(boolean value) {
+ if (myXBreakpoint instanceof XLineBreakpoint) {
+ ((XLineBreakpoint)myXBreakpoint).setTemporary(value);
+ }
+ }
+
@Nullable
public String getShortClassName() {
final String className = getClassName();
@@ -210,19 +237,19 @@ public abstract class Breakpoint extends FilteredRequestor implements ClassPrepa
private void runAction(final EvaluationContextImpl context, LocatableEvent event) {
final DebugProcessImpl debugProcess = context.getDebugProcess();
- if (LOG_ENABLED || LOG_EXPRESSION_ENABLED) {
+ if (isLogEnabled() || isLogExpressionEnabled()) {
final StringBuilder buf = StringBuilderSpinAllocator.alloc();
try {
- if (LOG_ENABLED) {
+ if (myXBreakpoint.isLogMessage()) {
buf.append(getEventMessage(event));
buf.append("\n");
}
- final TextWithImports expressionToEvaluate = getLogMessage();
- if (LOG_EXPRESSION_ENABLED && expressionToEvaluate != null && !"".equals(expressionToEvaluate.getText())) {
+ if (isLogExpressionEnabled()) {
if(!debugProcess.isAttached()) {
return;
}
-
+
+ final TextWithImports expressionToEvaluate = getLogMessage();
try {
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(getProject(), new EvaluatingComputable<ExpressionEvaluator>() {
@Override
@@ -252,11 +279,112 @@ public abstract class Breakpoint extends FilteredRequestor implements ClassPrepa
StringBuilderSpinAllocator.dispose(buf);
}
}
- if (REMOVE_AFTER_HIT) {
+ if (isRemoveAfterHit()) {
handleTemporaryBreakpointHit(debugProcess);
}
}
+ /**
+ * @return true if the ID was added or false otherwise
+ */
+ private boolean hasObjectID(long id) {
+ for (InstanceFilter instanceFilter : getInstanceFilters()) {
+ if (instanceFilter.getId() == id) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean evaluateCondition(final EvaluationContextImpl context, LocatableEvent event) throws EvaluateException {
+ if(isCountFilterEnabled()) {
+ final DebugProcessImpl debugProcess = context.getDebugProcess();
+ debugProcess.getVirtualMachineProxy().suspend();
+ debugProcess.getRequestsManager().deleteRequest(this);
+ ((Breakpoint)this).createRequest(debugProcess);
+ debugProcess.getVirtualMachineProxy().resume();
+ }
+ if (isInstanceFiltersEnabled()) {
+ Value value = context.getThisObject();
+ if (value != null) { // non-static
+ ObjectReference reference = (ObjectReference)value;
+ if(!hasObjectID(reference.uniqueID())) {
+ return false;
+ }
+ }
+ }
+
+ if (isClassFiltersEnabled()) {
+ String typeName = calculateEventClass(context, event);
+ if (!typeMatchesClassFilters(typeName)) return false;
+ }
+
+ if (isConditionEnabled() && !getCondition().getText().isEmpty()) {
+ try {
+ ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(context.getProject(), new EvaluatingComputable<ExpressionEvaluator>() {
+ public ExpressionEvaluator compute() throws EvaluateException {
+ final SourcePosition contextSourcePosition = ContextUtil.getSourcePosition(context);
+ // IMPORTANT: calculate context psi element basing on the location where the exception
+ // has been hit, not on the location where it was set. (For line breakpoints these locations are the same, however,
+ // for method, exception and field breakpoints these locations differ)
+ PsiElement contextPsiElement = ContextUtil.getContextElement(contextSourcePosition);
+ if (contextPsiElement == null) {
+ contextPsiElement = getEvaluationElement(); // as a last resort
+ }
+ return EvaluatorBuilderImpl.build(getCondition(), contextPsiElement, contextSourcePosition);
+ }
+ });
+ final Value value = evaluator.evaluate(context);
+ if (!(value instanceof BooleanValue)) {
+ throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.boolean.expected"));
+ }
+ if(!((BooleanValue)value).booleanValue()) {
+ return false;
+ }
+ }
+ catch (EvaluateException ex) {
+ if(ex.getCause() instanceof VMDisconnectedException) {
+ return false;
+ }
+ throw EvaluateExceptionUtil.createEvaluateException(
+ DebuggerBundle.message("error.failed.evaluating.breakpoint.condition", getCondition(), ex.getMessage())
+ );
+ }
+ return true;
+ }
+
+ return true;
+ }
+
+ protected String calculateEventClass(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException {
+ return event.location().declaringType().name();
+ }
+
+ private boolean typeMatchesClassFilters(@Nullable String typeName) {
+ if (typeName == null) {
+ return true;
+ }
+ boolean matches = false, hasEnabled = false;
+ for (ClassFilter classFilter : getClassFilters()) {
+ if (classFilter.isEnabled()) {
+ hasEnabled = true;
+ if (classFilter.matches(typeName)) {
+ matches = true;
+ break;
+ }
+ }
+ }
+ if(hasEnabled && !matches) {
+ return false;
+ }
+ for (ClassFilter classFilter : getClassExclusionFilters()) {
+ if (classFilter.isEnabled() && classFilter.matches(typeName)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private void handleTemporaryBreakpointHit(final DebugProcessImpl debugProcess) {
debugProcess.addDebugProcessListener(new DebugProcessAdapter() {
@Override
@@ -288,26 +416,213 @@ public abstract class Breakpoint extends FilteredRequestor implements ClassPrepa
RequestManagerImpl.deleteRequests(this);
}
- @Override
public void readExternal(Element parentNode) throws InvalidDataException {
- super.readExternal(parentNode);
- String logMessage = JDOMExternalizerUtil.readField(parentNode, LOG_MESSAGE_OPTION_NAME);
- if (logMessage != null) {
- setLogMessage(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, logMessage));
+ FilteredRequestorImpl requestor = new FilteredRequestorImpl(myProject);
+ requestor.readTo(parentNode, this);
+ try {
+ setEnabled(Boolean.valueOf(JDOMExternalizerUtil.readField(parentNode, "ENABLED")));
+ } catch (Exception e) {
}
+ try {
+ setLogEnabled(Boolean.valueOf(JDOMExternalizerUtil.readField(parentNode, "LOG_ENABLED")));
+ } catch (Exception e) {
+ }
+ try {
+ if (Boolean.valueOf(JDOMExternalizerUtil.readField(parentNode, "LOG_EXPRESSION_ENABLED"))) {
+ String logMessage = JDOMExternalizerUtil.readField(parentNode, LOG_MESSAGE_OPTION_NAME);
+ if (logMessage != null) {
+ setLogMessage(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, logMessage));
+ }
+ }
+ } catch (Exception e) {
+ }
+ try {
+ setRemoveAfterHit(Boolean.valueOf(JDOMExternalizerUtil.readField(parentNode, "REMOVE_AFTER_HIT")));
+ } catch (Exception e) {
+ }
+ }
+
+ //@Override
+ //public void writeExternal(Element parentNode) throws WriteExternalException {
+ //super.writeExternal(parentNode);
+ //JDOMExternalizerUtil.writeField(parentNode, LOG_MESSAGE_OPTION_NAME, getLogMessage().toExternalForm());
+ //}
+
+ //public void setLogMessage(TextWithImports logMessage) {
+ // myLogMessage = logMessage;
+ //}
+
+ public abstract PsiElement getEvaluationElement();
+
+ protected TextWithImports getLogMessage() {
+ return new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, myXBreakpoint.getLogExpression());
+ }
+
+ protected TextWithImports getCondition() {
+ return new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, myXBreakpoint.getCondition());
+ }
+
+ public boolean isEnabled() {
+ return myXBreakpoint.isEnabled();
+ }
+
+ public void setEnabled(boolean enabled) {
+ myXBreakpoint.setEnabled(enabled);
+ }
+
+ protected boolean isLogEnabled() {
+ return myXBreakpoint.isLogMessage();
+ }
+
+ public void setLogEnabled(boolean logEnabled) {
+ myXBreakpoint.setLogMessage(logEnabled);
+ }
+
+ protected boolean isLogExpressionEnabled() {
+ String expression = myXBreakpoint.getLogExpression();
+ if (expression == null || expression.isEmpty()) {
+ return false;
+ }
+ return !getLogMessage().isEmpty();
+ }
+
+ @Override
+ public boolean isCountFilterEnabled() {
+ if (getProperties() == null) {
+ return false;
+ }
+ return getProperties().COUNT_FILTER_ENABLED;
+ }
+ public void setCountFilterEnabled(boolean enabled) {
+ getProperties().COUNT_FILTER_ENABLED = enabled;
+ }
+
+ @Override
+ public int getCountFilter() {
+ return getProperties().COUNT_FILTER;
+ }
+
+ public void setCountFilter(int filter) {
+ getProperties().COUNT_FILTER = filter;
+ }
+
+ @Override
+ public boolean isClassFiltersEnabled() {
+ if (getProperties() == null) {
+ return false;
+ }
+ return getProperties().CLASS_FILTERS_ENABLED;
+ }
+
+ public void setClassFiltersEnabled(boolean enabled) {
+ getProperties().CLASS_FILTERS_ENABLED = enabled;
+ }
+
+ @Override
+ public ClassFilter[] getClassFilters() {
+ return getProperties().getClassFilters();
+ }
+
+ public void setClassFilters(ClassFilter[] filters) {
+ getProperties().setClassFilters(filters);
+ }
+
+ @Override
+ public ClassFilter[] getClassExclusionFilters() {
+ return getProperties().getClassExclusionFilters();
+ }
+
+ protected void setClassExclusionFilters(ClassFilter[] filters) {
+ getProperties().setClassExclusionFilters(filters);
+ }
+
+ @Override
+ public boolean isInstanceFiltersEnabled() {
+ if (getProperties() == null) {
+ return false;
+ }
+ return getProperties().INSTANCE_FILTERS_ENABLED;
+ }
+
+ public void setInstanceFiltersEnabled(boolean enabled) {
+ getProperties().INSTANCE_FILTERS_ENABLED = enabled;
}
@Override
- public void writeExternal(Element parentNode) throws WriteExternalException {
- super.writeExternal(parentNode);
- JDOMExternalizerUtil.writeField(parentNode, LOG_MESSAGE_OPTION_NAME, getLogMessage().toExternalForm());
+ public InstanceFilter[] getInstanceFilters() {
+ return getProperties().getInstanceFilters();
+ }
+
+ public void setInstanceFilters(InstanceFilter[] filters) {
+ getProperties().setInstanceFilters(filters);
+ }
+
+ private static String getSuspendPolicy(XBreakpoint breakpoint) {
+ switch (breakpoint.getSuspendPolicy()) {
+ case ALL:
+ return DebuggerSettings.SUSPEND_ALL;
+ case THREAD:
+ return DebuggerSettings.SUSPEND_THREAD;
+ case NONE:
+ return DebuggerSettings.SUSPEND_NONE;
+
+ default:
+ throw new IllegalArgumentException("unknown suspend policy");
+ }
+ }
+
+ static SuspendPolicy transformSuspendPolicy(String policy) {
+ if (DebuggerSettings.SUSPEND_ALL.equals(policy)) {
+ return SuspendPolicy.ALL;
+ } else if (DebuggerSettings.SUSPEND_THREAD.equals(policy)) {
+ return SuspendPolicy.THREAD;
+ } else if (DebuggerSettings.SUSPEND_NONE.equals(policy)) {
+ return SuspendPolicy.NONE;
+ } else {
+ throw new IllegalArgumentException("unknown suspend policy");
+ }
}
- public TextWithImports getLogMessage() {
- return myLogMessage;
+ protected boolean isSuspend() {
+ return myXBreakpoint.getSuspendPolicy() != SuspendPolicy.NONE;
+ }
+
+ @Override
+ public String getSuspendPolicy() {
+ return getSuspendPolicy(myXBreakpoint);
+ }
+
+ public void setSuspendPolicy(String policy) {
+ myXBreakpoint.setSuspendPolicy(transformSuspendPolicy(policy));
+ }
+
+ protected void setLogMessage(@Nullable TextWithImports logMessage) {
+ if (logMessage != null && !logMessage.getText().isEmpty()) {
+ myXBreakpoint.setLogExpression(logMessage.toExternalForm());
+ }
+ else {
+ myXBreakpoint.setLogExpression(null);
+ }
+ }
+
+ protected boolean isConditionEnabled() {
+ String condition = myXBreakpoint.getCondition();
+ if (condition == null || condition.isEmpty()) {
+ return false;
+ }
+ return !getCondition().isEmpty();
+ }
+
+ public void setCondition(@Nullable TextWithImports condition) {
+ if (condition != null && !condition.getText().isEmpty()) {
+ myXBreakpoint.setCondition(condition.toExternalForm());
+ }
+ else {
+ myXBreakpoint.setCondition(null);
+ }
}
- public void setLogMessage(TextWithImports logMessage) {
- myLogMessage = logMessage;
+ protected void addInstanceFilter(long l) {
+ getProperties().addInstanceFilter(l);
}
}