IDEA-139959 Freeze on evaluate expression action invocation.
authorEgor.Ushakov <egor.ushakov@jetbrains.com>
Tue, 12 May 2015 17:27:05 +0000 (20:27 +0300)
committerEgor.Ushakov <egor.ushakov@jetbrains.com>
Tue, 12 May 2015 17:42:09 +0000 (20:42 +0300)
java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java
platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValue.java
platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java
platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java
platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java
platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTreePanel.java
platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/EvaluateInConsoleFromTreeAction.java
platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesAction.java

index 16fdaad1eab66515239c8a5ff406326126e01156..dcc54be00a2ce98a2e29293c0e9eaf8c4c7d2841 100644 (file)
@@ -54,6 +54,8 @@ import com.sun.jdi.ArrayType;
 import com.sun.jdi.Value;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.jetbrains.concurrency.AsyncPromise;
+import org.jetbrains.concurrency.Promise;
 
 import javax.swing.*;
 import java.util.ArrayList;
@@ -457,14 +459,17 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
     return myValueDescriptor.canSetValue() ? new JavaValueModifier(this) : null;
   }
 
-
   private volatile String evaluationExpression = null;
-  @Nullable
+
+  @NotNull
   @Override
-  public String getEvaluationExpression() {
-    if (evaluationExpression == null) {
-      // TODO: change API to allow to calculate it asynchronously
-      myEvaluationContext.getManagerThread().invokeAndWait(new SuspendContextCommandImpl(myEvaluationContext.getSuspendContext()) {
+  public Promise<String> calculateEvaluationExpression() {
+    if (evaluationExpression != null) {
+      return Promise.resolve(evaluationExpression);
+    }
+    else {
+      final AsyncPromise<String> res = new AsyncPromise<String>();
+      myEvaluationContext.getManagerThread().schedule(new SuspendContextCommandImpl(myEvaluationContext.getSuspendContext()) {
         @Override
         public Priority getPriority() {
           return Priority.HIGH;
@@ -487,10 +492,11 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
               return null;
             }
           });
+          res.setResult(evaluationExpression);
         }
       });
+      return res;
     }
-    return evaluationExpression;
   }
 
   @Override
index 64c0d900b29deac6aca71e5afcedff158f3913af..82539889ed86385c8494e119662793b0d93a1db7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2015 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ import com.intellij.util.ThreeState;
 import com.intellij.xdebugger.evaluation.XInstanceEvaluator;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.jetbrains.concurrency.Promise;
 
 /**
  * Represents a value in debugger tree.
@@ -44,6 +45,14 @@ public abstract class XValue extends XValueContainer {
     return null;
   }
 
+  /**
+   * Asynchronously calculates expression which evaluates to the current value
+   */
+  @NotNull
+  public Promise<String> calculateEvaluationExpression() {
+    return Promise.resolve(getEvaluationExpression());
+  }
+
   /**
    * @return evaluator to calculate value of the current object instance
    */
index b6875bec0664b18250c168302185ba4a10eeb01a..fc274d686245e2a1fe23c5361b0ad3fedff3b5ba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2015 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,6 +23,8 @@ import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.ui.AppUIUtil;
+import com.intellij.util.Consumer;
 import com.intellij.xdebugger.XDebugSession;
 import com.intellij.xdebugger.XExpression;
 import com.intellij.xdebugger.XSourcePosition;
@@ -45,8 +47,8 @@ import org.jetbrains.annotations.Nullable;
 public class XDebuggerEvaluateActionHandler extends XDebuggerActionHandler {
   @Override
   protected void perform(@NotNull final XDebugSession session, final DataContext dataContext) {
-    XDebuggerEditorsProvider editorsProvider = session.getDebugProcess().getEditorsProvider();
-    XStackFrame stackFrame = session.getCurrentStackFrame();
+    final XDebuggerEditorsProvider editorsProvider = session.getDebugProcess().getEditorsProvider();
+    final XStackFrame stackFrame = session.getCurrentStackFrame();
     final XDebuggerEvaluator evaluator = session.getDebugProcess().getEvaluator();
     if (evaluator == null) {
       return;
@@ -72,10 +74,29 @@ public class XDebuggerEvaluateActionHandler extends XDebuggerActionHandler {
     if (text == null) {
       XValue value = XDebuggerTreeActionBase.getSelectedValue(dataContext);
       if (value != null) {
-        text = value.getEvaluationExpression();
+        final EvaluationMode evalMode = mode;
+        value.calculateEvaluationExpression().done(new Consumer<String>() {
+          @Override
+          public void consume(final String text) {
+            AppUIUtil.invokeOnEdt(new Runnable() {
+              @Override
+              public void run() {
+                showDialog(session, dataContext, editorsProvider, stackFrame, evaluator, evalMode, text);
+              }
+            });
+          }
+        });
+        return;
       }
     }
 
+    showDialog(session, dataContext, editorsProvider, stackFrame, evaluator, mode, text);
+  }
+
+  private static void showDialog(@NotNull XDebugSession session,
+                                 DataContext dataContext,
+                                 XDebuggerEditorsProvider editorsProvider,
+                                 XStackFrame stackFrame, XDebuggerEvaluator evaluator, EvaluationMode mode, String text) {
     Language language = null;
     if (stackFrame != null) {
       XSourcePosition position = stackFrame.getSourcePosition();
index 533cae3e07d3c8146bacf0414a15fa5c306e7127..8c2e7d0aed8273dd04c59962cf75bc9c935ffcf0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2015 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@ import com.intellij.openapi.util.SystemInfo;
 import com.intellij.ui.*;
 import com.intellij.ui.border.CustomLineBorder;
 import com.intellij.util.Alarm;
+import com.intellij.util.Consumer;
 import com.intellij.util.ui.UIUtil;
 import com.intellij.util.ui.tree.TreeUtil;
 import com.intellij.xdebugger.XDebugSession;
@@ -432,11 +433,15 @@ public class XWatchesViewImpl extends XDebugView implements DnDNativeTarget, XWa
     if (object instanceof XValueNodeImpl[]) {
       final XValueNodeImpl[] nodes = (XValueNodeImpl[])object;
       for (XValueNodeImpl node : nodes) {
-        String expression = node.getValueContainer().getEvaluationExpression();
-        if (expression != null) {
-          //noinspection ConstantConditions
-          addWatchExpression(XExpressionImpl.fromText(expression), -1, false);
-        }
+        node.getValueContainer().calculateEvaluationExpression().done(new Consumer<String>() {
+          @Override
+          public void consume(String expression) {
+            if (expression != null) {
+              //noinspection ConstantConditions
+              addWatchExpression(XExpressionImpl.fromText(expression), -1, false);
+            }
+          }
+        });
       }
     }
     else if (object instanceof EventInfo) {
index 063226f82f76d27fd846bbcfb94199614d594529..c0110780674c8ea45fe32586d249b50f71d70a03 100644 (file)
@@ -25,6 +25,7 @@ import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.popup.*;
 import com.intellij.openapi.util.Computable;
 import com.intellij.openapi.util.DimensionService;
+import com.intellij.openapi.util.Getter;
 import com.intellij.openapi.util.Ref;
 import com.intellij.openapi.wm.IdeFocusManager;
 import com.intellij.openapi.wm.WindowManager;
@@ -38,6 +39,7 @@ import com.intellij.xdebugger.breakpoints.XBreakpointAdapter;
 import com.intellij.xdebugger.breakpoints.XBreakpointListener;
 import com.intellij.xdebugger.breakpoints.XBreakpointManager;
 import com.intellij.xdebugger.frame.XFullValueEvaluator;
+import com.intellij.xdebugger.frame.XValue;
 import com.intellij.xdebugger.impl.breakpoints.XBreakpointBase;
 import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointsDialogFactory;
 import com.intellij.xdebugger.impl.breakpoints.ui.XLightBreakpointPropertiesPanel;
@@ -45,6 +47,7 @@ import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.jetbrains.concurrency.Promise;
 
 import javax.swing.*;
 import java.awt.*;
@@ -346,4 +349,16 @@ public class DebuggerUIUtil {
       return valueNode.getRawValue();
     }
   }
+
+  /**
+   * Checks if value has evaluation expression ready, or calculation is pending
+   */
+  public static boolean hasEvaluationExpression(@NotNull XValue value) {
+    Promise<String> promise = value.calculateEvaluationExpression();
+    if (promise.getState() == Promise.State.PENDING) return true;
+    if (promise instanceof Getter) {
+      return ((Getter)promise).get() != null;
+    }
+    return true;
+  }
 }
index 1a4c5604ed183f2e0d7da22eb57977b4d4803953..0cc1cf7b285dc5c0eb9cc89d14a8eab6cd0935f7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2015 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@ import com.intellij.xdebugger.XDebuggerBundle;
 import com.intellij.xdebugger.XSourcePosition;
 import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
 import com.intellij.xdebugger.impl.frame.XValueMarkers;
+import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
 import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
@@ -70,7 +71,7 @@ public class XDebuggerTreePanel implements DnDSource {
     return myTree.getSelectedNodes(XValueNodeImpl.class, new Tree.NodeFilter<XValueNodeImpl>() {
       @Override
       public boolean accept(final XValueNodeImpl node) {
-        return node.getValueContainer().getEvaluationExpression() != null;
+        return DebuggerUIUtil.hasEvaluationExpression(node.getValueContainer());
       }
     });
   }
index 8f515ee5907e2f0e03d2ed2f84e0140822f6ce37..29cd6b9d6133e5b085f8f0a679580d7c4d6d033b 100644 (file)
@@ -1,8 +1,24 @@
+/*
+ * Copyright 2000-2015 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.intellij.xdebugger.impl.ui.tree.actions;
 
 import com.intellij.execution.console.ConsoleExecuteAction;
 import com.intellij.openapi.actionSystem.AnActionEvent;
 import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.util.Consumer;
 import com.intellij.xdebugger.impl.actions.handlers.XEvaluateInConsoleFromEditorActionHandler;
 import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
 import org.jetbrains.annotations.NotNull;
@@ -32,12 +48,16 @@ class EvaluateInConsoleFromTreeAction extends XAddToWatchesAction {
 
   @Override
   protected void perform(XValueNodeImpl node, @NotNull String nodeName, AnActionEvent e) {
-    ConsoleExecuteAction action = getConsoleExecuteAction(e);
+    final ConsoleExecuteAction action = getConsoleExecuteAction(e);
     if (action != null) {
-      String expression = node.getValueContainer().getEvaluationExpression();
-      if (expression != null) {
-        action.execute(null, expression, null);
-      }
+      node.getValueContainer().calculateEvaluationExpression().done(new Consumer<String>() {
+        @Override
+        public void consume(String expression) {
+          if (expression != null) {
+            action.execute(null, expression, null);
+          }
+        }
+      });
     }
   }
 }
\ No newline at end of file
index 211fddae40ea37d80f220b31db26c45b11423923..3cf3114d430f162e67580521873151e44e00b58d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2015 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,11 +18,13 @@ package com.intellij.xdebugger.impl.ui.tree.actions;
 import com.intellij.openapi.actionSystem.AnActionEvent;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.Consumer;
 import com.intellij.xdebugger.XDebugSession;
 import com.intellij.xdebugger.XDebuggerManager;
 import com.intellij.xdebugger.impl.XDebugSessionImpl;
 import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl;
 import com.intellij.xdebugger.impl.frame.XWatchesView;
+import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
 import com.intellij.xdebugger.impl.ui.XDebugSessionTab;
 import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
 import org.jetbrains.annotations.NotNull;
@@ -33,17 +35,21 @@ import org.jetbrains.annotations.NotNull;
 class XAddToWatchesAction extends XDebuggerTreeActionBase {
   @Override
   protected boolean isEnabled(@NotNull final XValueNodeImpl node, @NotNull AnActionEvent e) {
-    return super.isEnabled(node, e) && node.getValueContainer().getEvaluationExpression() != null && getWatchesView(e) != null;
+    return super.isEnabled(node, e) && DebuggerUIUtil.hasEvaluationExpression(node.getValueContainer()) && getWatchesView(e) != null;
   }
 
   @Override
   protected void perform(final XValueNodeImpl node, @NotNull final String nodeName, final AnActionEvent e) {
-    XWatchesView watchesView = getWatchesView(e);
+    final XWatchesView watchesView = getWatchesView(e);
     if (watchesView != null) {
-      String expression = node.getValueContainer().getEvaluationExpression();
-      if (!StringUtil.isEmpty(expression)) {
-        watchesView.addWatchExpression(XExpressionImpl.fromText(expression), -1, true);
-      }
+      node.getValueContainer().calculateEvaluationExpression().done(new Consumer<String>() {
+        @Override
+        public void consume(String expression) {
+          if (!StringUtil.isEmpty(expression)) {
+            watchesView.addWatchExpression(XExpressionImpl.fromText(expression), -1, true);
+          }
+        }
+      });
     }
   }