f16ee5c7987a972e88f08b036ed2b0f214a1a175
[idea/community.git] / python / src / com / jetbrains / python / debugger / PyDebugProcess.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.jetbrains.python.debugger;
17
18 import com.google.common.base.Strings;
19 import com.google.common.collect.Lists;
20 import com.google.common.collect.Maps;
21 import com.intellij.execution.process.ProcessEvent;
22 import com.intellij.execution.process.ProcessHandler;
23 import com.intellij.execution.process.ProcessListener;
24 import com.intellij.execution.ui.ConsoleView;
25 import com.intellij.execution.ui.ConsoleViewContentType;
26 import com.intellij.execution.ui.ExecutionConsole;
27 import com.intellij.openapi.actionSystem.AnActionEvent;
28 import com.intellij.openapi.actionSystem.DefaultActionGroup;
29 import com.intellij.openapi.actionSystem.Presentation;
30 import com.intellij.openapi.actionSystem.ToggleAction;
31 import com.intellij.openapi.application.AccessToken;
32 import com.intellij.openapi.application.ApplicationInfo;
33 import com.intellij.openapi.application.ApplicationManager;
34 import com.intellij.openapi.diagnostic.Logger;
35 import com.intellij.openapi.editor.Document;
36 import com.intellij.openapi.extensions.Extensions;
37 import com.intellij.openapi.fileEditor.FileDocumentManager;
38 import com.intellij.openapi.module.Module;
39 import com.intellij.openapi.module.ModuleUtilCore;
40 import com.intellij.openapi.progress.ProgressIndicator;
41 import com.intellij.openapi.progress.ProgressManager;
42 import com.intellij.openapi.progress.Task;
43 import com.intellij.openapi.project.Project;
44 import com.intellij.openapi.ui.Messages;
45 import com.intellij.openapi.util.Key;
46 import com.intellij.openapi.util.Ref;
47 import com.intellij.openapi.vfs.VirtualFile;
48 import com.intellij.psi.PsiElement;
49 import com.intellij.psi.PsiFile;
50 import com.intellij.psi.PsiManager;
51 import com.intellij.psi.ResolveState;
52 import com.intellij.psi.scope.PsiScopeProcessor;
53 import com.intellij.psi.util.PsiTreeUtil;
54 import com.intellij.remote.RemoteProcessControl;
55 import com.intellij.util.ui.UIUtil;
56 import com.intellij.xdebugger.*;
57 import com.intellij.xdebugger.breakpoints.*;
58 import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
59 import com.intellij.xdebugger.frame.XExecutionStack;
60 import com.intellij.xdebugger.frame.XStackFrame;
61 import com.intellij.xdebugger.frame.XSuspendContext;
62 import com.intellij.xdebugger.frame.XValueChildrenList;
63 import com.intellij.xdebugger.stepping.XSmartStepIntoHandler;
64 import com.jetbrains.python.PythonFileType;
65 import com.jetbrains.python.console.PythonConsoleView;
66 import com.jetbrains.python.console.PythonDebugLanguageConsoleView;
67 import com.jetbrains.python.console.pydev.PydevCompletionVariant;
68 import com.jetbrains.python.debugger.pydev.*;
69 import com.jetbrains.python.debugger.settings.PyDebuggerSettings;
70 import com.jetbrains.python.psi.*;
71 import com.jetbrains.python.psi.resolve.PyResolveContext;
72 import com.jetbrains.python.psi.resolve.PyResolveUtil;
73 import com.jetbrains.python.psi.resolve.RatedResolveResult;
74 import com.jetbrains.python.psi.types.PyClassType;
75 import com.jetbrains.python.psi.types.PyModuleType;
76 import com.jetbrains.python.psi.types.PyType;
77 import com.jetbrains.python.psi.types.PyTypeParser;
78 import org.jetbrains.annotations.NotNull;
79 import org.jetbrains.annotations.Nullable;
80
81 import java.io.IOException;
82 import java.net.ServerSocket;
83 import java.util.*;
84 import java.util.concurrent.ConcurrentHashMap;
85
86 import static javax.swing.SwingUtilities.invokeLater;
87
88 /**
89  * @author yole
90  */
91 // todo: bundle messages
92 // todo: pydevd supports module reloading - look for a way to use the feature
93 public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, ProcessListener {
94
95   private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.debugger.PyDebugProcess");
96   private static final int CONNECTION_TIMEOUT = 60000;
97
98   private final ProcessDebugger myDebugger;
99   private final XBreakpointHandler[] myBreakpointHandlers;
100   private final PyDebuggerEditorsProvider myEditorsProvider;
101   private final ProcessHandler myProcessHandler;
102   private final ExecutionConsole myExecutionConsole;
103   private final Map<PySourcePosition, XLineBreakpoint> myRegisteredBreakpoints = new ConcurrentHashMap<>();
104   private final Map<String, XBreakpoint<? extends ExceptionBreakpointProperties>> myRegisteredExceptionBreakpoints =
105     new ConcurrentHashMap<>();
106
107   private final List<PyThreadInfo> mySuspendedThreads = Collections.synchronizedList(Lists.<PyThreadInfo>newArrayList());
108   private final Map<String, XValueChildrenList> myStackFrameCache = Maps.newHashMap();
109   private final Map<String, PyDebugValue> myNewVariableValue = Maps.newHashMap();
110   private boolean myDownloadSources = false;
111
112   private boolean myClosing = false;
113
114   private PyPositionConverter myPositionConverter;
115   private final XSmartStepIntoHandler<?> mySmartStepIntoHandler;
116   private boolean myWaitingForConnection = false;
117   private PyStackFrame myConsoleContextFrame = null;
118   private PyReferrersLoader myReferrersProvider;
119
120   public PyDebugProcess(@NotNull XDebugSession session,
121                         @NotNull ServerSocket serverSocket,
122                         @NotNull ExecutionConsole executionConsole,
123                         @Nullable ProcessHandler processHandler, boolean multiProcess) {
124     this(session, multiProcess ? process -> process.createMultiprocessDebugger(serverSocket)
125                                : process -> new RemoteDebugger(process, serverSocket, process.getConnectTimeout()),
126          executionConsole, processHandler);
127   }
128
129   public PyDebugProcess(final @NotNull XDebugSession session,
130                         @NotNull final ExecutionConsole executionConsole,
131                         @Nullable final ProcessHandler processHandler,
132                         @NotNull String serverHost, int serverPort) {
133     this(session, process -> new ClientModeMultiProcessDebugger(process, serverHost, serverPort), executionConsole, processHandler);
134   }
135
136   private PyDebugProcess(@NotNull XDebugSession session,
137                         @NotNull DebuggerFactory debuggerFactory,
138                         @NotNull ExecutionConsole executionConsole,
139                         @Nullable ProcessHandler processHandler) {
140     super(session);
141
142     session.setPauseActionSupported(true);
143
144     myDebugger = debuggerFactory.createDebugger(this);
145
146     List<XBreakpointHandler> breakpointHandlers = new ArrayList<>();
147     breakpointHandlers.add(new PyLineBreakpointHandler(this));
148     breakpointHandlers.add(new PyExceptionBreakpointHandler(this));
149     for (PyBreakpointHandlerFactory factory : Extensions.getExtensions(PyBreakpointHandlerFactory.EP_NAME)) {
150       breakpointHandlers.add(factory.createBreakpointHandler(this));
151     }
152     myBreakpointHandlers = breakpointHandlers.toArray(new XBreakpointHandler[breakpointHandlers.size()]);
153
154     myEditorsProvider = new PyDebuggerEditorsProvider();
155     mySmartStepIntoHandler = new PySmartStepIntoHandler(this);
156     myProcessHandler = processHandler;
157     myExecutionConsole = executionConsole;
158     if (myProcessHandler != null) {
159       myProcessHandler.addProcessListener(this);
160     }
161     if (processHandler instanceof PositionConverterProvider) {
162       myPositionConverter = ((PositionConverterProvider)processHandler).createPositionConverter(this);
163     }
164     else {
165       myPositionConverter = new PyLocalPositionConverter();
166     }
167     myDebugger.addCloseListener(new RemoteDebuggerCloseListener() {
168       @Override
169       public void closed() {
170         handleStop();
171       }
172
173       @Override
174       public void communicationError() {
175         detachDebuggedProcess();
176       }
177
178       @Override
179       public void detached() {
180         detachDebuggedProcess();
181       }
182     });
183
184     session.addSessionListener(new XDebugSessionListener() {
185       @Override
186       public void stackFrameChanged() {
187         String currentFrameThreadId = null;
188         final XStackFrame currentFrame = session.getCurrentStackFrame();
189         if (currentFrame instanceof PyStackFrame) {
190           currentFrameThreadId = ((PyStackFrame)currentFrame).getThreadId();
191         }
192         final XExecutionStack activeStack = session.getSuspendContext().getActiveExecutionStack();
193         if ((activeStack == null) || (currentFrameThreadId == null)) {
194           return;
195         }
196         final XStackFrame frameFromSuspendContext = activeStack.getTopFrame();
197         String activeStackThreadId = null;
198         if (frameFromSuspendContext instanceof PyStackFrame) {
199           activeStackThreadId = ((PyStackFrame)frameFromSuspendContext).getThreadId();
200         }
201         if (!currentFrameThreadId.equals(activeStackThreadId)) {
202           // another thread was selected, we should update suspendContext
203           PyThreadInfo threadInfo = null;
204           for (PyThreadInfo info : mySuspendedThreads) {
205             if (info.getId().equals(currentFrameThreadId)) {
206               threadInfo = info;
207               break;
208             }
209           }
210           if (threadInfo != null) {
211             getSession().positionReached(createSuspendContext(threadInfo));
212           }
213         }
214       }
215     });
216   }
217
218   private MultiProcessDebugger createMultiprocessDebugger(ServerSocket serverSocket) {
219     MultiProcessDebugger debugger = new MultiProcessDebugger(this, serverSocket, 10000);
220     debugger.addOtherDebuggerCloseListener(new MultiProcessDebugger.DebuggerProcessListener() {
221       @Override
222       public void threadsClosed(Set<String> threadIds) {
223         for (PyThreadInfo t : mySuspendedThreads) {
224           if (threadIds.contains(t.getId())) {
225             if (getSession().isSuspended()) {
226               getSession().resume();
227               break;
228             }
229           }
230         }
231       }
232     });
233     return debugger;
234   }
235
236   protected void detachDebuggedProcess() {
237     handleStop(); //in case of normal debug we stop the session
238   }
239
240   protected void handleStop() {
241     getSession().stop();
242   }
243
244   public void setPositionConverter(PyPositionConverter positionConverter) {
245     myPositionConverter = positionConverter;
246   }
247
248
249   @Override
250   public PyPositionConverter getPositionConverter() {
251     return myPositionConverter;
252   }
253
254   @NotNull
255   @Override
256   public XBreakpointHandler<?>[] getBreakpointHandlers() {
257     return myBreakpointHandlers;
258   }
259
260   @Override
261   @NotNull
262   public XDebuggerEditorsProvider getEditorsProvider() {
263     return myEditorsProvider;
264   }
265
266   @Override
267   @Nullable
268   protected ProcessHandler doGetProcessHandler() {
269     return myProcessHandler;
270   }
271
272   @Override
273   @NotNull
274   public ExecutionConsole createConsole() {
275     return myExecutionConsole;
276   }
277
278   @Override
279   public XSmartStepIntoHandler<?> getSmartStepIntoHandler() {
280     return mySmartStepIntoHandler;
281   }
282
283   @Override
284   public void sessionInitialized() {
285     waitForConnection(getConnectionMessage(), getConnectionTitle());
286   }
287
288   protected void waitForConnection(final String connectionMessage, String connectionTitle) {
289     ProgressManager.getInstance().run(new Task.Backgroundable(getSession().getProject(), connectionTitle, false) {
290       @Override
291       public void run(@NotNull final ProgressIndicator indicator) {
292         indicator.setText(connectionMessage);
293         try {
294           beforeConnect();
295           myWaitingForConnection = true;
296           myDebugger.waitForConnect();
297           myWaitingForConnection = false;
298           afterConnect();
299
300           handshake();
301           init();
302           myDebugger.run();
303         }
304         catch (final Exception e) {
305           myWaitingForConnection = false;
306           if (myProcessHandler != null) {
307             myProcessHandler.destroyProcess();
308           }
309           if (!myClosing) {
310             invokeLater(
311               () -> Messages.showErrorDialog("Unable to establish connection with debugger:\n" + e.getMessage(), getConnectionTitle()));
312           }
313         }
314       }
315     });
316   }
317
318   @Override
319   public void init() {
320     getSession().rebuildViews();
321     registerBreakpoints();
322     setShowReturnValues(PyDebuggerSettings.getInstance().isWatchReturnValues());
323   }
324
325   @Override
326   public int handleDebugPort(int localPort) throws IOException {
327     if (myProcessHandler instanceof RemoteProcessControl) {
328       return getRemoteTunneledPort(localPort, (RemoteProcessControl)myProcessHandler);
329     }
330     else {
331       return localPort;
332     }
333   }
334
335   protected static int getRemoteTunneledPort(int localPort, @NotNull RemoteProcessControl handler) throws IOException {
336     try {
337       return handler.getRemoteSocket(localPort).getSecond();
338     }
339     catch (Exception e) {
340       throw new IOException(e);
341     }
342   }
343
344   @Override
345   public void recordSignature(PySignature signature) {
346     PySignatureCacheManager.getInstance(getSession().getProject()).recordSignature(myPositionConverter.convertSignature(signature));
347   }
348
349   @Override
350   public void recordLogEvent(PyConcurrencyEvent event) {
351     PyConcurrencyService.getInstance(getSession().getProject()).recordEvent(getSession(), event, event.isAsyncio());
352   }
353
354   @Override
355   public void showConsole(PyThreadInfo thread) {
356     myConsoleContextFrame = new PyExecutionStack(this, thread).getTopFrame();
357     if (myExecutionConsole instanceof PythonDebugLanguageConsoleView) {
358       PythonDebugLanguageConsoleView consoleView = (PythonDebugLanguageConsoleView)myExecutionConsole;
359       UIUtil.invokeLaterIfNeeded(() -> {
360         consoleView.enableConsole(false);
361         consoleView.getPydevConsoleView().setConsoleEnabled(true);
362       });
363     }
364   }
365
366   @Override
367   public void consoleInputRequested(boolean isStarted) {
368     if (myExecutionConsole instanceof PythonDebugLanguageConsoleView) {
369       PythonConsoleView consoleView = ((PythonDebugLanguageConsoleView)myExecutionConsole).getPydevConsoleView();
370       if (isStarted) {
371         consoleView.inputRequested();
372       }
373       else {
374         consoleView.inputReceived();
375       }
376     }
377   }
378
379   protected void afterConnect() {
380   }
381
382   protected void beforeConnect() {
383   }
384
385   protected String getConnectionMessage() {
386     return "Waiting for connection...";
387   }
388
389   protected String getConnectionTitle() {
390     return "Connecting To Debugger";
391   }
392
393   private void handshake() throws PyDebuggerException {
394     String remoteVersion = myDebugger.handshake();
395     String currentBuild = ApplicationInfo.getInstance().getBuild().asStringWithoutProductCode();
396     if ("@@BUILD_NUMBER@@".equals(remoteVersion)) {
397       remoteVersion = currentBuild;
398     }
399     else if (remoteVersion.startsWith("PY-")) {
400       remoteVersion = remoteVersion.substring(3);
401     }
402     else {
403       remoteVersion = null;
404     }
405     printToConsole("Connected to pydev debugger (build " + remoteVersion + ")\n", ConsoleViewContentType.SYSTEM_OUTPUT);
406
407     if (remoteVersion != null) {
408       if (!(remoteVersion.equals(currentBuild) || remoteVersion.startsWith(currentBuild))) {
409         LOG.warn(String.format("Wrong debugger version. Remote version: %s Current build: %s", remoteVersion, currentBuild));
410         printToConsole("Warning: wrong debugger version. Use pycharm-debugger.egg from PyCharm installation folder.\n",
411                        ConsoleViewContentType.ERROR_OUTPUT);
412       }
413     }
414   }
415
416   @Override
417   public void printToConsole(String text, ConsoleViewContentType contentType) {
418     ((ConsoleView)myExecutionConsole).print(text, contentType);
419   }
420
421   private void registerBreakpoints() {
422     registerLineBreakpoints();
423     registerExceptionBreakpoints();
424   }
425
426   private void registerExceptionBreakpoints() {
427     for (XBreakpoint<? extends ExceptionBreakpointProperties> bp : myRegisteredExceptionBreakpoints.values()) {
428       addExceptionBreakpoint(bp);
429     }
430   }
431
432   public void registerLineBreakpoints() {
433     for (Map.Entry<PySourcePosition, XLineBreakpoint> entry : myRegisteredBreakpoints.entrySet()) {
434       addBreakpoint(entry.getKey(), entry.getValue());
435     }
436   }
437
438   @Override
439   public void registerAdditionalActions(@NotNull DefaultActionGroup leftToolbar,
440                                         @NotNull DefaultActionGroup topToolbar,
441                                         @NotNull DefaultActionGroup settings) {
442     super.registerAdditionalActions(leftToolbar, topToolbar, settings);
443     settings.add(new WatchReturnValuesAction(this));
444     settings.add(new SimplifiedView(this));
445   }
446
447   private static class WatchReturnValuesAction extends ToggleAction {
448     private volatile boolean myWatchesReturnValues;
449     private final PyDebugProcess myProcess;
450     private final String myText;
451
452     public WatchReturnValuesAction(@NotNull PyDebugProcess debugProcess) {
453       super("", "Enables watching executed functions return values", null);
454       myWatchesReturnValues = PyDebuggerSettings.getInstance().isWatchReturnValues();
455       myProcess = debugProcess;
456       myText = "Show Return Values";
457     }
458
459     @Override
460     public void update(@NotNull final AnActionEvent e) {
461       super.update(e);
462       final Presentation presentation = e.getPresentation();
463       presentation.setEnabled(true);
464       presentation.setText(myText);
465     }
466
467     @Override
468     public boolean isSelected(AnActionEvent e) {
469       return myWatchesReturnValues;
470     }
471
472     @Override
473     public void setSelected(AnActionEvent e, boolean watch) {
474       myWatchesReturnValues = watch;
475       PyDebuggerSettings.getInstance().setWatchReturnValues(watch);
476       final Project project = e.getProject();
477       if (project != null) {
478         myProcess.setShowReturnValues(myWatchesReturnValues);
479         myProcess.getSession().rebuildViews();
480       }
481     }
482   }
483
484   private static class SimplifiedView extends ToggleAction {
485     private volatile boolean mySimplifiedView;
486     private final PyDebugProcess myProcess;
487     private final String myText;
488
489     public SimplifiedView(@NotNull PyDebugProcess debugProcess) {
490       super("", "Disables watching classes, functions and modules objects", null);
491       mySimplifiedView = PyDebuggerSettings.getInstance().isSimplifiedView();
492       myProcess = debugProcess;
493       myText = "Simplified Variables View";
494     }
495
496     @Override
497     public void update(@NotNull final AnActionEvent e) {
498       super.update(e);
499       final Presentation presentation = e.getPresentation();
500       presentation.setEnabled(true);
501       presentation.setText(myText);
502     }
503
504     @Override
505     public boolean isSelected(AnActionEvent e) {
506       return mySimplifiedView;
507     }
508
509     @Override
510     public void setSelected(AnActionEvent e, boolean hide) {
511       mySimplifiedView = hide;
512       PyDebuggerSettings.getInstance().setSimplifiedView(hide);
513       myProcess.getSession().rebuildViews();
514     }
515   }
516
517   public void setShowReturnValues(boolean showReturnValues) {
518     myDebugger.setShowReturnValues(showReturnValues);
519   }
520
521   @Override
522   public void startStepOver(@Nullable XSuspendContext context) {
523     passToCurrentThread(context, ResumeOrStepCommand.Mode.STEP_OVER);
524   }
525
526   @Override
527   public void startStepInto(@Nullable XSuspendContext context) {
528     passToCurrentThread(context, ResumeOrStepCommand.Mode.STEP_INTO);
529   }
530
531   public void startStepIntoMyCode(@Nullable XSuspendContext context) {
532     if (!checkCanPerformCommands()) return;
533     getSession().sessionResumed();
534     passToCurrentThread(context, ResumeOrStepCommand.Mode.STEP_INTO_MY_CODE);
535   }
536
537   @Override
538   public void startStepOut(@Nullable XSuspendContext context) {
539     passToCurrentThread(context, ResumeOrStepCommand.Mode.STEP_OUT);
540   }
541
542   public void startSmartStepInto(String functionName) {
543     dropFrameCaches();
544     if (isConnected()) {
545       for (PyThreadInfo suspendedThread : mySuspendedThreads) {
546         myDebugger.smartStepInto(suspendedThread.getId(), functionName);
547       }
548     }
549   }
550
551   @Override
552   public void stop() {
553     myDebugger.close();
554   }
555
556   @Override
557   public void resume(@Nullable XSuspendContext context) {
558     passToAllThreads(ResumeOrStepCommand.Mode.RESUME);
559   }
560
561   @Override
562   public void startPausing() {
563     if (isConnected()) {
564       myDebugger.suspendAllThreads();
565     }
566   }
567
568   public void suspendAllOtherThreads(PyThreadInfo thread) {
569     myDebugger.suspendOtherThreads(thread);
570   }
571
572   /**
573    * Check if there is the thread suspended on the breakpoint with "Suspend all" policy
574    *
575    * @return true if this thread exists
576    */
577   @Override
578   public boolean isSuspendedOnAllThreadsPolicy() {
579     if (getSession().isSuspended()) {
580       for (PyThreadInfo threadInfo : getThreads()) {
581         final List<PyStackFrameInfo> frames = threadInfo.getFrames();
582         if ((threadInfo.getState() == PyThreadInfo.State.SUSPENDED) && (frames != null)) {
583           XBreakpoint<?> breakpoint = null;
584           if (threadInfo.isStopOnBreakpoint()) {
585             final PySourcePosition position = frames.get(0).getPosition();
586             breakpoint = myRegisteredBreakpoints.get(position);
587           }
588           else if (threadInfo.isExceptionBreak()) {
589             String exceptionName = threadInfo.getMessage();
590             if (exceptionName != null) {
591               breakpoint = myRegisteredExceptionBreakpoints.get(exceptionName);
592             }
593           }
594           if ((breakpoint != null) && (breakpoint.getType().isSuspendThreadSupported()) &&
595               (breakpoint.getSuspendPolicy() == SuspendPolicy.ALL)) {
596             return true;
597           }
598         }
599       }
600     }
601     return false;
602   }
603
604   private void passToAllThreads(final ResumeOrStepCommand.Mode mode) {
605     dropFrameCaches();
606     if (isConnected()) {
607       for (PyThreadInfo thread : myDebugger.getThreads()) {
608         myDebugger.resumeOrStep(thread.getId(), mode);
609       }
610     }
611   }
612
613   private void passToCurrentThread(@Nullable XSuspendContext context, final ResumeOrStepCommand.Mode mode) {
614     dropFrameCaches();
615     if (isConnected()) {
616       String threadId = threadIdBeforeResumeOrStep(context);
617
618       for (PyThreadInfo suspendedThread : mySuspendedThreads) {
619         if (threadId == null || threadId.equals(suspendedThread.getId())) {
620           myDebugger.resumeOrStep(suspendedThread.getId(), mode);
621           break;
622         }
623       }
624     }
625   }
626
627   @Nullable
628   private static String threadIdBeforeResumeOrStep(@Nullable XSuspendContext context) {
629     if (context instanceof PySuspendContext) {
630       return ((PySuspendContext)context).getActiveExecutionStack().getThreadId();
631     }
632     else {
633       return null;
634     }
635   }
636
637   protected boolean isConnected() {
638     return myDebugger.isConnected();
639   }
640
641   protected void disconnect() {
642     myDebugger.disconnect();
643     cleanUp();
644   }
645
646   public boolean isDownloadSources() {
647     return myDownloadSources;
648   }
649
650   public void setDownloadSources(boolean downloadSources) {
651     myDownloadSources = downloadSources;
652   }
653
654   protected void cleanUp() {
655     mySuspendedThreads.clear();
656     myDownloadSources = false;
657   }
658
659   @Override
660   public void runToPosition(@NotNull final XSourcePosition position, @Nullable XSuspendContext context) {
661     dropFrameCaches();
662     if (isConnected() && !mySuspendedThreads.isEmpty()) {
663       final PySourcePosition pyPosition = myPositionConverter.convertToPython(position);
664       String type = PyLineBreakpointType.ID;
665       AccessToken lock = ApplicationManager.getApplication().acquireReadActionLock();
666       try {
667         final Document document = FileDocumentManager.getInstance().getDocument(position.getFile());
668         if (document != null) {
669           for (XBreakpointType breakpointType : Extensions.getExtensions(XBreakpointType.EXTENSION_POINT_NAME)) {
670             if (breakpointType instanceof PyBreakpointType &&
671                 ((PyBreakpointType)breakpointType).canPutInDocument(getSession().getProject(), document)) {
672               type = breakpointType.getId();
673               break;
674             }
675           }
676         }
677       }
678       finally {
679         lock.finish();
680       }
681       myDebugger.setTempBreakpoint(type, pyPosition.getFile(), pyPosition.getLine());
682
683       passToCurrentThread(context, ResumeOrStepCommand.Mode.RESUME);
684     }
685   }
686
687   @Override
688   public PyDebugValue evaluate(final String expression, final boolean execute, boolean doTrunc) throws PyDebuggerException {
689     dropFrameCaches();
690     final PyStackFrame frame = currentFrame();
691     return evaluate(expression, execute, frame, doTrunc);
692   }
693
694   private PyDebugValue evaluate(String expression, boolean execute, PyStackFrame frame, boolean trimResult) throws PyDebuggerException {
695     return myDebugger.evaluate(frame.getThreadId(), frame.getFrameId(), expression, execute, trimResult);
696   }
697
698   public void consoleExec(String command, PyDebugCallback<String> callback) {
699     dropFrameCaches();
700     try {
701       final PyStackFrame frame = currentFrame();
702       myDebugger.consoleExec(frame.getThreadId(), frame.getFrameId(), command, callback);
703     }
704     catch (PyDebuggerException e) {
705       callback.error(e);
706     }
707   }
708
709   @Override
710   @Nullable
711   public XValueChildrenList loadFrame() throws PyDebuggerException {
712     final PyStackFrame frame = currentFrame();
713     //do not reload frame every time it is needed, because due to bug in pdb, reloading frame clears all variable changes
714     if (!myStackFrameCache.containsKey(frame.getThreadFrameId())) {
715       XValueChildrenList values = myDebugger.loadFrame(frame.getThreadId(), frame.getFrameId());
716       myStackFrameCache.put(frame.getThreadFrameId(), values);
717     }
718     return applyNewValue(myStackFrameCache.get(frame.getThreadFrameId()), frame.getThreadFrameId());
719   }
720
721   private XValueChildrenList applyNewValue(XValueChildrenList pyDebugValues, String threadFrameId) {
722     if (myNewVariableValue.containsKey(threadFrameId)) {
723       PyDebugValue newValue = myNewVariableValue.get(threadFrameId);
724       XValueChildrenList res = new XValueChildrenList();
725       for (int i = 0; i < pyDebugValues.size(); i++) {
726         final String name = pyDebugValues.getName(i);
727         if (name.equals(newValue.getName())) {
728           res.add(name, newValue);
729         }
730         else {
731           res.add(name, pyDebugValues.getValue(i));
732         }
733       }
734       return res;
735     }
736     else {
737       return pyDebugValues;
738     }
739   }
740
741   @Override
742   public XValueChildrenList loadVariable(final PyDebugValue var) throws PyDebuggerException {
743     final PyStackFrame frame = currentFrame();
744     PyDebugValue debugValue = var.setName(var.getFullName());
745     return myDebugger.loadVariable(frame.getThreadId(), frame.getFrameId(), debugValue);
746   }
747
748   @Override
749   public void loadReferrers(PyReferringObjectsValue var, PyDebugCallback<XValueChildrenList> callback) {
750     try {
751       final PyStackFrame frame = currentFrame();
752       myDebugger.loadReferrers(frame.getThreadId(), frame.getFrameId(), var, callback);
753     }
754     catch (PyDebuggerException e) {
755       callback.error(e);
756     }
757   }
758
759   @Override
760   public void changeVariable(final PyDebugValue var, final String value) throws PyDebuggerException {
761     final PyStackFrame frame = currentFrame();
762     PyDebugValue newValue = myDebugger.changeVariable(frame.getThreadId(), frame.getFrameId(), var, value);
763     myNewVariableValue.put(frame.getThreadFrameId(), newValue);
764   }
765
766   @Nullable
767   @Override
768   public PyReferrersLoader getReferrersLoader() {
769     if (myReferrersProvider == null) {
770       myReferrersProvider = new PyReferrersLoader(this);
771     }
772     return myReferrersProvider;
773   }
774
775   @Override
776   public ArrayChunk getArrayItems(PyDebugValue var, int rowOffset, int colOffset, int rows, int cols, String format)
777     throws PyDebuggerException {
778     final PyStackFrame frame = currentFrame();
779     return myDebugger.loadArrayItems(frame.getThreadId(), frame.getFrameId(), var, rowOffset, colOffset, rows, cols, format);
780   }
781
782   @Nullable
783   public String loadSource(String path) {
784     return myDebugger.loadSource(path);
785   }
786
787   @Override
788   public boolean canSaveToTemp(String name) {
789     final Project project = getSession().getProject();
790     return PyDebugSupportUtils.canSaveToTemp(project, name);
791   }
792
793   @NotNull
794   private PyStackFrame currentFrame() throws PyDebuggerException {
795     if (!isConnected()) {
796       throw new PyDebuggerException("Disconnected");
797     }
798
799     final PyStackFrame frame = (PyStackFrame)getSession().getCurrentStackFrame();
800
801     if (frame == null && myConsoleContextFrame != null) {
802       return myConsoleContextFrame;
803     }
804
805     if (frame == null) {
806       throw new PyDebuggerException("Process is running");
807     }
808
809     return frame;
810   }
811
812   @Nullable
813   private String getFunctionName(final XLineBreakpoint breakpoint) {
814     if (breakpoint.getSourcePosition() == null) {
815       return null;
816     }
817     final VirtualFile file = breakpoint.getSourcePosition().getFile();
818     AccessToken lock = ApplicationManager.getApplication().acquireReadActionLock();
819     try {
820       final Document document = FileDocumentManager.getInstance().getDocument(file);
821       final Project project = getSession().getProject();
822       if (document != null) {
823         if (file.getFileType() == PythonFileType.INSTANCE) {
824           PsiElement psiElement = XDebuggerUtil.getInstance().
825             findContextElement(file, document.getLineStartOffset(breakpoint.getSourcePosition().getLine()), project, false);
826           PyFunction function = PsiTreeUtil.getParentOfType(psiElement, PyFunction.class);
827           if (function != null) {
828             return function.getName();
829           }
830         }
831       }
832       return null;
833     }
834     finally {
835       lock.finish();
836     }
837   }
838
839   public void addBreakpoint(final PySourcePosition position, final XLineBreakpoint breakpoint) {
840     myRegisteredBreakpoints.put(position, breakpoint);
841     if (isConnected()) {
842       final String conditionExpression = breakpoint.getConditionExpression() == null
843                                          ? null
844                                          : breakpoint.getConditionExpression().getExpression();
845       final String logExpression = breakpoint.getLogExpressionObject() == null
846                                    ? null
847                                    : breakpoint.getLogExpressionObject().getExpression();
848       SuspendPolicy policy = breakpoint.getType().isSuspendThreadSupported()? breakpoint.getSuspendPolicy(): SuspendPolicy.NONE;
849       myDebugger.setBreakpoint(breakpoint.getType().getId(),
850                                position.getFile(),
851                                position.getLine(),
852                                conditionExpression,
853                                logExpression,
854                                getFunctionName(breakpoint),
855                                policy
856       );
857     }
858   }
859
860   public void addTemporaryBreakpoint(String typeId, String file, int line) {
861     if (isConnected()) {
862       myDebugger.setTempBreakpoint(typeId, file, line);
863     }
864   }
865
866   public void removeBreakpoint(final PySourcePosition position) {
867     XLineBreakpoint breakpoint = myRegisteredBreakpoints.get(position);
868     if (breakpoint != null) {
869       myRegisteredBreakpoints.remove(position);
870       if (isConnected()) {
871         myDebugger.removeBreakpoint(breakpoint.getType().getId(), position.getFile(), position.getLine());
872       }
873     }
874   }
875
876   public void addExceptionBreakpoint(XBreakpoint<? extends ExceptionBreakpointProperties> breakpoint) {
877     myRegisteredExceptionBreakpoints.put(breakpoint.getProperties().getException(), breakpoint);
878     if (isConnected()) {
879       myDebugger.addExceptionBreakpoint(breakpoint.getProperties());
880     }
881   }
882
883   public void removeExceptionBreakpoint(XBreakpoint<? extends ExceptionBreakpointProperties> breakpoint) {
884     myRegisteredExceptionBreakpoints.remove(breakpoint.getProperties().getException());
885     if (isConnected()) {
886       myDebugger.removeExceptionBreakpoint(breakpoint.getProperties());
887     }
888   }
889
890   public Collection<PyThreadInfo> getThreads() {
891     return myDebugger.getThreads();
892   }
893
894   @Override
895   public void threadSuspended(final PyThreadInfo threadInfo, boolean updateSourcePosition) {
896     if (!mySuspendedThreads.contains(threadInfo)) {
897       mySuspendedThreads.add(threadInfo);
898
899       final List<PyStackFrameInfo> frames = threadInfo.getFrames();
900       if (frames != null) {
901         final PySuspendContext suspendContext = createSuspendContext(threadInfo);
902
903         XBreakpoint<?> breakpoint = null;
904         if (threadInfo.isStopOnBreakpoint()) {
905           final PySourcePosition position = frames.get(0).getPosition();
906           breakpoint = myRegisteredBreakpoints.get(position);
907           if (breakpoint == null) {
908             myDebugger.removeTempBreakpoint(position.getFile(), position.getLine());
909           }
910         }
911         else if (threadInfo.isExceptionBreak()) {
912           String exceptionName = threadInfo.getMessage();
913           threadInfo.setMessage(null);
914           if (exceptionName != null) {
915             breakpoint = myRegisteredExceptionBreakpoints.get(exceptionName);
916           }
917         }
918         if (breakpoint != null) {
919           if ((breakpoint.getType().isSuspendThreadSupported()) && (breakpoint.getSuspendPolicy() == SuspendPolicy.ALL)) {
920             suspendAllOtherThreads(threadInfo);
921           }
922         }
923
924         if (updateSourcePosition) {
925           if (breakpoint != null) {
926             if (!getSession().breakpointReached(breakpoint, threadInfo.getMessage(), suspendContext)) {
927               resume(suspendContext);
928             }
929           }
930           else {
931             getSession().positionReached(suspendContext);
932           }
933         }
934       }
935     }
936   }
937
938   @NotNull
939   protected PySuspendContext createSuspendContext(PyThreadInfo threadInfo) {
940     return new PySuspendContext(this, threadInfo);
941   }
942
943   @Override
944   public void threadResumed(final PyThreadInfo threadInfo) {
945     mySuspendedThreads.remove(threadInfo);
946   }
947
948   private void dropFrameCaches() {
949     myStackFrameCache.clear();
950     myNewVariableValue.clear();
951   }
952
953   @NotNull
954   public List<PydevCompletionVariant> getCompletions(String prefix) throws Exception {
955     if (isConnected()) {
956       dropFrameCaches();
957       final PyStackFrame frame = currentFrame();
958       return myDebugger.getCompletions(frame.getThreadId(), frame.getFrameId(), prefix);
959     }
960     return Lists.newArrayList();
961   }
962
963   @NotNull
964   public String getDescription(String prefix) throws Exception {
965     if (isConnected()) {
966       dropFrameCaches();
967       final PyStackFrame frame = currentFrame();
968       return myDebugger.getDescription(frame.getThreadId(), frame.getFrameId(), prefix);
969     }
970     return "";
971   }
972
973
974   @Override
975   public void startNotified(ProcessEvent event) {
976   }
977
978   @Override
979   public void processTerminated(ProcessEvent event) {
980     myDebugger.close();
981   }
982
983   @Override
984   public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
985     myClosing = true;
986   }
987
988   @Override
989   public void onTextAvailable(ProcessEvent event, Key outputType) {
990   }
991
992   public PyStackFrame createStackFrame(PyStackFrameInfo frameInfo) {
993     return new PyStackFrame(getSession().getProject(), this, frameInfo,
994                             getPositionConverter().convertFromPython(frameInfo.getPosition()));
995   }
996
997   @Override
998   public String getCurrentStateMessage() {
999     if (getSession().isStopped()) {
1000       return XDebuggerBundle.message("debugger.state.message.disconnected");
1001     }
1002     else if (isConnected()) {
1003       return XDebuggerBundle.message("debugger.state.message.connected");
1004     }
1005     else {
1006       return getConnectionMessage();
1007     }
1008   }
1009
1010   public void addProcessListener(ProcessListener listener) {
1011     ProcessHandler handler = doGetProcessHandler();
1012     if (handler != null) {
1013       handler.addProcessListener(listener);
1014     }
1015   }
1016
1017   public boolean isWaitingForConnection() {
1018     return myWaitingForConnection;
1019   }
1020
1021   public void setWaitingForConnection(boolean waitingForConnection) {
1022     myWaitingForConnection = waitingForConnection;
1023   }
1024
1025   public int getConnectTimeout() {
1026     return CONNECTION_TIMEOUT;
1027   }
1028
1029
1030   @Nullable
1031   private XSourcePosition getCurrentFrameSourcePosition() {
1032     try {
1033       PyStackFrame frame = currentFrame();
1034
1035       return frame.getSourcePosition();
1036     }
1037     catch (PyDebuggerException e) {
1038       return null;
1039     }
1040   }
1041
1042   public Project getProject() {
1043     return getSession().getProject();
1044   }
1045
1046   @Nullable
1047   @Override
1048   public XSourcePosition getSourcePositionForName(String name, String parentType) {
1049     if (name == null) return null;
1050     XSourcePosition currentPosition = getCurrentFrameSourcePosition();
1051
1052     final PsiFile file = getPsiFile(currentPosition);
1053
1054     if (file == null) return null;
1055
1056     if (Strings.isNullOrEmpty(parentType)) {
1057       final Ref<PsiElement> elementRef = resolveInCurrentFrame(name, currentPosition, file);
1058       return elementRef.isNull() ? null : XDebuggerUtil.getInstance().createPositionByElement(elementRef.get());
1059     }
1060     else {
1061       final PyType parentDef = resolveTypeFromString(parentType, file);
1062       if (parentDef == null) {
1063         return null;
1064       }
1065       List<? extends RatedResolveResult> results =
1066         parentDef.resolveMember(name, null, AccessDirection.READ, PyResolveContext.noImplicits());
1067       if (results != null && !results.isEmpty()) {
1068         return XDebuggerUtil.getInstance().createPositionByElement(results.get(0).getElement());
1069       }
1070       else {
1071         return typeToPosition(parentDef); // at least try to return parent
1072       }
1073     }
1074   }
1075
1076
1077   @NotNull
1078   private static Ref<PsiElement> resolveInCurrentFrame(final String name, XSourcePosition currentPosition, PsiFile file) {
1079     final Ref<PsiElement> elementRef = Ref.create();
1080     PsiElement currentElement = file.findElementAt(currentPosition.getOffset());
1081
1082     if (currentElement == null) {
1083       return elementRef;
1084     }
1085
1086
1087     PyResolveUtil.scopeCrawlUp(new PsiScopeProcessor() {
1088       @Override
1089       public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) {
1090         if ((element instanceof PyImportElement)) {
1091           PyImportElement importElement = (PyImportElement)element;
1092           if (name.equals(importElement.getVisibleName())) {
1093             if (elementRef.isNull()) {
1094               elementRef.set(element);
1095             }
1096             return false;
1097           }
1098           return true;
1099         }
1100         else {
1101           if (elementRef.isNull()) {
1102             elementRef.set(element);
1103           }
1104           return false;
1105         }
1106       }
1107
1108       @Nullable
1109       @Override
1110       public <T> T getHint(@NotNull Key<T> hintKey) {
1111         return null;
1112       }
1113
1114       @Override
1115       public void handleEvent(@NotNull Event event, @Nullable Object associated) {
1116
1117       }
1118     }, currentElement, name, null);
1119     return elementRef;
1120   }
1121
1122   @Nullable
1123   private PsiFile getPsiFile(XSourcePosition currentPosition) {
1124     if (currentPosition == null) {
1125       return null;
1126     }
1127
1128     return PsiManager.getInstance(getProject()).findFile(currentPosition.getFile());
1129   }
1130
1131
1132   @Nullable
1133   @Override
1134   public XSourcePosition getSourcePositionForType(String typeName) {
1135     XSourcePosition currentPosition = getCurrentFrameSourcePosition();
1136
1137     final PsiFile file = getPsiFile(currentPosition);
1138
1139     if (file == null || typeName == null || !(file instanceof PyFile)) return null;
1140
1141
1142     final PyType pyType = resolveTypeFromString(typeName, file);
1143     return pyType == null ? null : typeToPosition(pyType);
1144   }
1145
1146   @Nullable
1147   private static XSourcePosition typeToPosition(PyType pyType) {
1148     final PyClassType classType = PyUtil.as(pyType, PyClassType.class);
1149
1150     if (classType != null) {
1151       return XDebuggerUtil.getInstance().createPositionByElement(classType.getPyClass());
1152     }
1153
1154     final PyModuleType moduleType = PyUtil.as(pyType, PyModuleType.class);
1155     if (moduleType != null) {
1156       return XDebuggerUtil.getInstance().createPositionByElement(moduleType.getModule());
1157     }
1158     return null;
1159   }
1160
1161   private PyType resolveTypeFromString(String typeName, PsiFile file) {
1162     typeName = typeName.replace("__builtin__.", "");
1163     PyType pyType = null;
1164     if (!typeName.contains(".")) {
1165
1166       pyType = PyTypeParser.getTypeByName(file, typeName);
1167     }
1168     if (pyType == null) {
1169       PyElementGenerator generator = PyElementGenerator.getInstance(getProject());
1170       PyPsiFacade psiFacade = PyPsiFacade.getInstance(getProject());
1171       PsiFile dummyFile = generator.createDummyFile(((PyFile)file).getLanguageLevel(), "");
1172       Module moduleForFile = ModuleUtilCore.findModuleForPsiElement(file);
1173       dummyFile.putUserData(ModuleUtilCore.KEY_MODULE, moduleForFile);
1174
1175       pyType = psiFacade.parseTypeAnnotation(typeName, dummyFile);
1176     }
1177     return pyType;
1178   }
1179
1180   private interface DebuggerFactory {
1181     @NotNull ProcessDebugger createDebugger(@NotNull PyDebugProcess process);
1182   }
1183 }