Merge pull request #383 (https://github.com/JetBrains/intellij-community/pull/383)
authorElizaveta Shashkova <Elizaveta.Shashkova@jetbrains.com>
Tue, 19 Apr 2016 14:22:53 +0000 (17:22 +0300)
committerElizaveta Shashkova <Elizaveta.Shashkova@jetbrains.com>
Tue, 19 Apr 2016 14:22:53 +0000 (17:22 +0300)
12 files changed:
python/helpers/pydev/_pydevd_bundle/pydevd_xml.py
python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java
python/pydevSrc/com/jetbrains/python/debugger/PyFrameAccessor.java
python/pydevSrc/com/jetbrains/python/debugger/PyReferringObjectsValue.java
python/pydevSrc/com/jetbrains/python/debugger/pydev/GetFrameCommand.java
python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java
python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java
python/src/com/jetbrains/python/console/PydevConsoleCommunication.java
python/src/com/jetbrains/python/debugger/PyDebugProcess.java
python/src/com/jetbrains/python/debugger/PyDebuggerEvaluator.java
python/src/com/jetbrains/python/debugger/array/AsyncArrayTableModel.java
python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java

index 56cd26b1a675ab4d756870c8053541a747212972..e3ef8f87454e9c874281c91b3739870a3865e44e 100644 (file)
@@ -176,6 +176,9 @@ def frame_vars_to_xml(frame_f_locals):
     return xml
 
 
+def get_type_qualifier(type):
+    return getattr(type, "__module__", "")
+
 def var_to_xml(val, name, doTrim=True, additionalInXml=''):
     """ single variable or dictionary to xml representation """
 
@@ -187,6 +190,8 @@ def var_to_xml(val, name, doTrim=True, additionalInXml=''):
         v = val
 
     _type, typeName, resolver = get_type(v)
+    type_qualifier = get_type_qualifier(_type)
+
 
     do_not_call_value_str = False
     if isinstance(resolver, pydevd_resolver.djangoFormResolver.__class__):
@@ -233,7 +238,7 @@ def var_to_xml(val, name, doTrim=True, additionalInXml=''):
         name = quote(name, '/>_= ') #TODO: Fix PY-5834 without using quote
     except:
         pass
-    xml = '<var name="%s" type="%s"' % (make_valid_xml_value(name), make_valid_xml_value(typeName))
+    xml = '<var name="%s" type="%s" qualifier="%s"' % (make_valid_xml_value(name), make_valid_xml_value(typeName), make_valid_xml_value(type_qualifier))
 
     if value:
         #cannot be too big... communication may not handle it.
index e0962e5f6aea872668adde891e2930ca706bcc79..02b1b591684eb6f9d800d5a4f90ebad1fede078b 100644 (file)
@@ -1,5 +1,6 @@
 package com.jetbrains.python.debugger;
 
+import com.google.common.base.Strings;
 import com.intellij.icons.AllIcons;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.diagnostic.Logger;
@@ -9,6 +10,8 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 // todo: load long lists by parts
 // todo: null modifier for modify modules, class objects etc.
@@ -18,6 +21,7 @@ public class PyDebugValue extends XNamedValue {
 
   private String myTempName = null;
   private final String myType;
+  private final String myTypeQualifier;
   private final String myValue;
   private final boolean myContainer;
   private final PyDebugValue myParent;
@@ -29,15 +33,16 @@ public class PyDebugValue extends XNamedValue {
 
   private final boolean myErrorOnEval;
 
-  public PyDebugValue(@NotNull final String name, final String type, final String value, final boolean container,
+  public PyDebugValue(@NotNull final String name, final String type, String typeQualifier, final String value, final boolean container,
                       boolean errorOnEval, final PyFrameAccessor frameAccessor) {
-    this(name, type, value, container, errorOnEval, null, frameAccessor);
+    this(name, type, typeQualifier, value, container, errorOnEval, null, frameAccessor);
   }
 
-  public PyDebugValue(@NotNull final String name, final String type, final String value, final boolean container,
+  public PyDebugValue(@NotNull final String name, final String type, String typeQualifier, final String value, final boolean container,
                       boolean errorOnEval, final PyDebugValue parent, final PyFrameAccessor frameAccessor) {
     super(name);
     myType = type;
+    myTypeQualifier = Strings.isNullOrEmpty(typeQualifier) ? null : typeQualifier;
     myValue = value;
     myContainer = container;
     myErrorOnEval = errorOnEval;
@@ -70,7 +75,7 @@ public class PyDebugValue extends XNamedValue {
   }
   
   public PyDebugValue setParent(@Nullable PyDebugValue parent) {
-    return new PyDebugValue(myName, myType, myValue, myContainer, myErrorOnEval, parent, myFrameAccessor);
+    return new PyDebugValue(myName, myType, myTypeQualifier, myValue, myContainer, myErrorOnEval, parent, myFrameAccessor);
   }
 
   public PyDebugValue getParent() {
@@ -213,7 +218,7 @@ public class PyDebugValue extends XNamedValue {
   }
   
   public PyDebugValue setName(String newName) {
-    return new PyDebugValue(newName, myType, myValue, myContainer, myErrorOnEval, myParent, myFrameAccessor);
+    return new PyDebugValue(newName, myType, myTypeQualifier, myValue, myContainer, myErrorOnEval, myParent, myFrameAccessor);
   }
 
   @Nullable
@@ -258,7 +263,13 @@ public class PyDebugValue extends XNamedValue {
 
   @Override
   public void computeSourcePosition(@NotNull XNavigatable navigatable) {
-    navigatable.setSourcePosition(myFrameAccessor.getSourcePositionForName(myName));
+    if (myParent == null) {
+      navigatable.setSourcePosition(myFrameAccessor.getSourcePositionForName(myName, null));
+    }
+    else
+    {
+      navigatable.setSourcePosition(myFrameAccessor.getSourcePositionForName(myName, myParent.getDeclaringType()));
+    }
   }
 
   @Override
@@ -266,8 +277,34 @@ public class PyDebugValue extends XNamedValue {
     return true;
   }
 
+  private static final  Pattern IS_TYPE_DECLARATION = Pattern.compile("<(?:class|type)\\s*'(?<TYPE>.*?)'>");
   @Override
   public void computeTypeSourcePosition(@NotNull XNavigatable navigatable) {
-    navigatable.setSourcePosition(myFrameAccessor.getSourcePositionForType(myType));
+
+    String lookupType = getDeclaringType();
+    navigatable.setSourcePosition(myFrameAccessor.getSourcePositionForType(lookupType));
+  }
+
+  protected final String getDeclaringType() {
+    String lookupType = getQualifiedType();
+    if (!Strings.isNullOrEmpty(myValue))
+    {
+      Matcher matcher = IS_TYPE_DECLARATION.matcher(myValue);
+      if (matcher.matches())
+      {
+        lookupType = matcher.group("TYPE");
+      }
+    }
+    return lookupType;
+  }
+
+  public String getQualifiedType() {
+    if (Strings.isNullOrEmpty(myType))
+      return null;
+    return (myTypeQualifier == null) ? myType : (myTypeQualifier + "." + myType);
+  }
+
+  public String getTypeQualifier() {
+    return myTypeQualifier;
   }
 }
index bd6d5449a51d5309d5fadebfeb74fa3c97221d73..0bb4ee11606a1778eb7b901baf783f1de48a0841 100644 (file)
@@ -25,7 +25,7 @@ public interface PyFrameAccessor {
   ArrayChunk getArrayItems(PyDebugValue var, int rowOffset, int colOffset, int rows, int cols, String format) throws PyDebuggerException;
 
   @Nullable
-  XSourcePosition getSourcePositionForName(String name);
+  XSourcePosition getSourcePositionForName(String name, String parentType);
 
   @Nullable
   XSourcePosition getSourcePositionForType(String type);
index 283653659d0dda698838d81ad618eb58df5d0037..3493e164558130562c7719b20f4ed368b5e2150d 100644 (file)
@@ -28,14 +28,15 @@ public class PyReferringObjectsValue extends PyDebugValue {
 
   public PyReferringObjectsValue(@NotNull String name,
                                  String type,
+                                 String typeQualifier,
                                  String value,
                                  boolean container, boolean errorOnEval, @NotNull PyFrameAccessor frameAccessor) {
-    super(name, type, value, container, errorOnEval, frameAccessor);
+    super(name, type, typeQualifier, value, container, errorOnEval, frameAccessor);
     myReferrersLoader = frameAccessor.getReferrersLoader();
   }
 
   public PyReferringObjectsValue(PyDebugValue debugValue) {
-    this(debugValue.getName(), debugValue.getType(), debugValue.getValue(), debugValue.isContainer(), debugValue.isErrorOnEval(), debugValue.getFrameAccessor());
+    this(debugValue.getName(), debugValue.getType(), debugValue.getTypeQualifier(), debugValue.getValue(), debugValue.isContainer(), debugValue.isErrorOnEval(), debugValue.getFrameAccessor());
   }
 
   @Override
index 9df4ffa092dfff90e43a1ed3bc60d74cc6d8c65d..7a854b961fe53e0fa62caa5fe7d38556f3046088 100644 (file)
@@ -47,7 +47,7 @@ public class GetFrameCommand extends AbstractFrameCommand {
   }
 
   protected PyDebugValue extend(final PyDebugValue value) {
-    return new PyDebugValue(value.getName(), value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(), null, myDebugProcess);
+    return new PyDebugValue(value.getName(), value.getType(), value.getTypeQualifier(), value.getValue(), value.isContainer(), value.isErrorOnEval(), null, myDebugProcess);
   }
 
   public XValueChildrenList getVariables() {
index 466780066f773fbd1bf72e46d4fdcdacfe2765a6..cc054917fdd1f86f310cab5dedcbf98f5e6a5af7 100644 (file)
@@ -50,7 +50,7 @@ public class GetVariableCommand extends GetFrameCommand {
 
   @Override
   protected PyDebugValue extend(final PyDebugValue value) {
-    return new PyDebugValue(value.getName(), value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(), myParent,
+    return new PyDebugValue(value.getName(), value.getType(), value.getTypeQualifier(), value.getValue(), value.isContainer(), value.isErrorOnEval(), myParent,
                             myDebugProcess);
   }
 }
index ea4d5173b31bd112d5767f96af9142b1fb589b9c..6af8638d905204cf22ea79997536517ca031b937 100644 (file)
@@ -252,6 +252,8 @@ public class ProtocolParser {
 
     final String name = readString(reader, "name", null);
     final String type = readString(reader, "type", null);
+    final String qualifier = readString(reader, "qualifier", null); //to be able to get the fully qualified type if necessary
+
     String value = readString(reader, "value", null);
     final String isContainer = readString(reader, "isContainer", "");
     final String isErrorOnEval = readString(reader, "isErrorOnEval", "");
@@ -260,7 +262,7 @@ public class ProtocolParser {
       value = value.substring(type.length() + 2);
     }
 
-    return new PyDebugValue(name, type, value, "True".equals(isContainer), "True".equals(isErrorOnEval), frameAccessor);
+    return new PyDebugValue(name, type, qualifier, value, "True".equals(isContainer), "True".equals(isErrorOnEval), frameAccessor);
   }
 
   public static ArrayChunk parseArrayValues(final String text, final PyFrameAccessor frameAccessor) throws PyDebuggerException {
@@ -279,7 +281,7 @@ public class ProtocolParser {
       String max = readString(reader, "max", null);
       String min = readString(reader, "min", null);
       result =
-        new ArrayChunk(new PyDebugValue(slice, null, null, false, false, frameAccessor), slice, rows, cols, max, min, format, type, null);
+        new ArrayChunk(new PyDebugValue(slice, null, null, null, false, false, frameAccessor), slice, rows, cols, max, min, format, type, null);
       reader.moveUp();
     }
 
index 12815a3d82518b5d41e5da00c61a81e833fc9a48..af61cab907347228388245923243d60da8824036 100644 (file)
@@ -575,7 +575,7 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl
 
   @Nullable
   @Override
-  public XSourcePosition getSourcePositionForName(String name) {
+  public XSourcePosition getSourcePositionForName(String name, String parentType) {
     return null;
   }
 
index cf08a9ec0ecf356dd1426f1fd3b177e43bb8931d..f79490821d0afb8ac1aeef742a7ce887b9deae4c 100644 (file)
@@ -15,6 +15,7 @@
  */
 package com.jetbrains.python.debugger;
 
+import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.intellij.execution.process.ProcessEvent;
@@ -30,6 +31,8 @@ import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Document;
 import com.intellij.openapi.extensions.Extensions;
 import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtilCore;
 import com.intellij.openapi.progress.ProgressIndicator;
 import com.intellij.openapi.progress.ProgressManager;
 import com.intellij.openapi.progress.Task;
@@ -60,10 +63,12 @@ import com.jetbrains.python.PythonFileType;
 import com.jetbrains.python.console.PythonDebugLanguageConsoleView;
 import com.jetbrains.python.console.pydev.PydevCompletionVariant;
 import com.jetbrains.python.debugger.pydev.*;
-import com.jetbrains.python.psi.PyFunction;
-import com.jetbrains.python.psi.PyImportElement;
+import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.resolve.PyResolveContext;
 import com.jetbrains.python.psi.resolve.PyResolveUtil;
+import com.jetbrains.python.psi.resolve.RatedResolveResult;
 import com.jetbrains.python.psi.types.PyClassType;
+import com.jetbrains.python.psi.types.PyModuleType;
 import com.jetbrains.python.psi.types.PyType;
 import com.jetbrains.python.psi.types.PyTypeParser;
 import org.jetbrains.annotations.NotNull;
@@ -838,30 +843,67 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
 
   @Nullable
   @Override
-  public XSourcePosition getSourcePositionForName(String name) {
+  public XSourcePosition getSourcePositionForName(String name, String parentType) {
+    if (name == null) return null;
     XSourcePosition currentPosition = getCurrentFrameSourcePosition();
 
     final PsiFile file = getPsiFile(currentPosition);
 
     if (file == null) return null;
 
+    if (Strings.isNullOrEmpty(parentType)) {
+      final Ref<PsiElement> elementRef = resolveInCurrentFrame(name, currentPosition, file);
+      return elementRef.isNull() ? null : XSourcePositionImpl.createByElement(elementRef.get());
+    }
+    else {
+      final PyType parentDef = resolveTypeFromString(parentType, file);
+      if (parentDef == null)
+        return null;
+      List<? extends RatedResolveResult> results =
+        parentDef.resolveMember(name, null, AccessDirection.READ, PyResolveContext.noImplicits());
+      if (results != null && !results.isEmpty()) {
+        return XSourcePositionImpl.createByElement(results.get(0).getElement());
+      }
+      else {
+          return typeToPosition(parentDef); // at least try to return parent
+      }
+
+    }
+
+  }
+
+
+
+  @NotNull
+  private static Ref<PsiElement> resolveInCurrentFrame(final String name, XSourcePosition currentPosition, PsiFile file) {
+    final Ref<PsiElement> elementRef = Ref.create();
     PsiElement currentElement = file.findElementAt(currentPosition.getOffset());
 
     if (currentElement == null) {
-      return null;
+      return elementRef;
     }
 
-    final Ref<PsiElement> elementRef = Ref.create();
 
     PyResolveUtil.scopeCrawlUp(new PsiScopeProcessor() {
       @Override
       public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) {
-        if (!(element instanceof PyImportElement)) {
+        if ((element instanceof PyImportElement)) {
+          PyImportElement importElement = (PyImportElement)element;
+          if (name.equals(importElement.getVisibleName())) {
+            if (elementRef.isNull()) {
+              elementRef.set(element);
+            }
+            return false;
+
+          }
+          return true;
+        }
+        else {
           if (elementRef.isNull()) {
             elementRef.set(element);
           }
+          return false;
         }
-        return false;
       }
 
       @Nullable
@@ -875,9 +917,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
 
       }
     }, currentElement, name, null);
-
-    return elementRef.isNull() ? null
-                               : XSourcePositionImpl.createByElement(elementRef.get());
+    return elementRef;
   }
 
   @Nullable
@@ -897,15 +937,47 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
 
     final PsiFile file = getPsiFile(currentPosition);
 
-    if (file == null) return null;
+    if (file == null || typeName == null || !(file instanceof PyFile)) return null;
 
 
-    PyType type = PyTypeParser.getTypeByName(file, typeName);
+    final PyType pyType = resolveTypeFromString(typeName, file);
+    return pyType == null? null : typeToPosition(pyType);
+
+  }
+
+  @Nullable
+  private static XSourcePosition typeToPosition(PyType pyType) {
+    final PyClassType classType = PyUtil.as(pyType, PyClassType.class);
 
-    if (type instanceof PyClassType) {
-      return XSourcePositionImpl.createByElement(((PyClassType)type).getPyClass());
+    if (classType != null) {
+      return XSourcePositionImpl.createByElement(classType.getPyClass());
     }
 
+    final PyModuleType moduleType = PyUtil.as(pyType, PyModuleType.class);
+    if (moduleType != null) {
+      return XSourcePositionImpl.createByElement(moduleType.getModule());
+    }
     return null;
   }
+
+  private PyType resolveTypeFromString(String typeName, PsiFile file) {
+    typeName = typeName.replace("__builtin__.", "");
+    PyType pyType = null;
+    if (!typeName.contains(".")) {
+
+      pyType = PyTypeParser.getTypeByName(file, typeName);
+    }
+    if (pyType == null)
+    {
+      PyElementGenerator generator = PyElementGenerator.getInstance(getProject());
+      PyPsiFacade psiFacade = PyPsiFacade.getInstance(getProject());
+      PsiFile dummyFile = generator.createDummyFile( ((PyFile)file).getLanguageLevel() , "");
+      Module moduleForFile = ModuleUtilCore.findModuleForPsiElement(file);
+      dummyFile.putUserData(ModuleUtilCore.KEY_MODULE, moduleForFile);
+
+      pyType = psiFacade.parseTypeAnnotation(typeName, dummyFile);
+
+    }
+    return pyType;
+  }
 }
index 7ee0e3f22f9718196178e555792c2e729731bc4a..29cef063f1b308d4c371e91e85e0395bc3ca998f 100644 (file)
@@ -28,7 +28,7 @@ import org.jetbrains.annotations.Nullable;
 
 public class PyDebuggerEvaluator extends XDebuggerEvaluator {
 
-  private static final PyDebugValue NONE = new PyDebugValue("", "NoneType", "None", false, false, null, null);
+  private static final PyDebugValue NONE = new PyDebugValue("", "NoneType", null, "None", false, false, null, null);
 
   private Project myProject;
   private final PyFrameAccessor myDebugProcess;
index 1947968c843e630ab7325ed5160109b3c31cba3f..a2b68cb8461d1f83807edcbf7562989bc202fe23 100644 (file)
@@ -51,7 +51,7 @@ public class AsyncArrayTableModel extends AbstractTableModel {
       public ListenableFuture<ArrayChunk> load(final Pair<Integer, Integer> key) throws Exception {
         final PyDebugValue value = myProvider.getDebugValue();
         final PyDebugValue slicedValue =
-          new PyDebugValue(myProvider.getSliceText(), value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(),
+          new PyDebugValue(myProvider.getSliceText(), value.getType(), value.getTypeQualifier(), value.getValue(), value.isContainer(), value.isErrorOnEval(),
                            value.getParent(), value.getFrameAccessor());
 
         ListenableFutureTask<ArrayChunk> task = ListenableFutureTask.create(new Callable<ArrayChunk>() {
index 1424140c8b78e7defc9a78c53fd0380f8aabefbb..0ae8bed9ebb9f2dedfbaa89f829d41ca05038db8 100644 (file)
  */
 package com.jetbrains.python.debugger.array;
 
-import com.google.common.util.concurrent.ListenableFutureTask;
 import com.intellij.codeInsight.hint.HintManager;
 import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.application.Result;
-import com.intellij.openapi.command.WriteCommandAction;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.RangeMarker;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Pair;
-import com.intellij.util.Consumer;
 import com.intellij.util.ui.UIUtil;
-import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
-import com.intellij.xdebugger.frame.XValue;
 import com.jetbrains.python.debugger.*;
 import org.jetbrains.annotations.NotNull;
 
-import javax.management.InvalidAttributeValueException;
 import javax.swing.*;
-import javax.swing.table.TableCellEditor;
 import java.awt.*;
 import java.awt.event.*;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -179,7 +165,7 @@ public class NumpyArrayTable {
         final PyDebugValue value = getDebugValue();
         PyDebugValue parent = value.getParent();
         final PyDebugValue slicedValue =
-          new PyDebugValue(slice, value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(),
+          new PyDebugValue(slice, value.getType(), null, value.getValue(), value.isContainer(), value.isErrorOnEval(),
                            parent, value.getFrameAccessor());
 
         final String format = getFormat().isEmpty() ? "%" : getFormat();