PY-20833 Fixed: __len__ is not inferred from len(...)-statement
authorSemyon Proshev <Semyon.Proshev@jetbrains.com>
Thu, 20 Oct 2016 17:47:13 +0000 (20:47 +0300)
committerSemyon Proshev <Semyon.Proshev@jetbrains.com>
Mon, 24 Oct 2016 14:39:29 +0000 (17:39 +0300)
 Update PyNamedParameterImpl.collectUsedAttributes to honour len(...)-statements

python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
python/testData/inspections/PyAugmentAssignmentInspection/sequenceConcatenation.py
python/testSrc/com/jetbrains/python/PyTypeTest.java

index 2efd41e93e621882dd2107e6123d7b5c85a43d34..3c23c6cbdca7682cf4243866eeb13d570c1e9005 100644 (file)
@@ -28,7 +28,10 @@ import com.intellij.psi.util.PsiTreeUtil;
 import com.intellij.util.IncorrectOperationException;
 import com.intellij.util.PlatformIcons;
 import com.intellij.util.Processor;
-import com.jetbrains.python.*;
+import com.jetbrains.python.PyElementTypes;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.PyTokenTypes;
+import com.jetbrains.python.PythonDialectsTokenSetProvider;
 import com.jetbrains.python.codeInsight.PyTypingTypeProvider;
 import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
 import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
@@ -337,6 +340,27 @@ public class PyNamedParameterImpl extends PyBaseElementImpl<PyNamedParameterStub
             }
           }
         }
+
+        @Override
+        public void visitPyCallExpression(PyCallExpression node) {
+          Optional
+            .ofNullable(node.getCallee())
+            .map(context::getType)
+            .map(type -> PyUtil.as(type, PyFunctionType.class))
+            .map(PyFunctionType::getCallable)
+            .map(PyCallable::getName)
+            .filter("len"::equals)
+            .ifPresent(
+              callable -> {
+                final PyReferenceExpression argument = node.getArgument(0, PyReferenceExpression.class);
+                if (argument != null && argument.getReference().isReferenceTo(PyNamedParameterImpl.this)) {
+                  result.add(PyNames.LEN);
+                }
+              }
+            );
+
+          super.visitPyCallExpression(node);
+        }
       });
     }
     return result;
index 6d239a1cddccc4c4a60e0507269a2c602b1e35b9..aaeee091670df80f7dd4749ecf28199457d5d0a2 100644 (file)
@@ -11,13 +11,12 @@ def expand(values1, values2):
     <weak_warning descr="Assignment can be replaced with augmented assignment">values1 = values1 + values2</weak_warning>
 
 
-#def expand(values1, values2):
-#    a = len(values1)
-#    b = len(values2)
-#
-#    values1 = values2 + values1
-#    values1 = values1 + values2
-#    inspection should suggest replacement only for the second assignment
+def expand(values1, values2):
+    a = len(values1)
+    b = len(values2)
+
+    values1 = values2 + values1
+    <weak_warning descr="Assignment can be replaced with augmented assignment">values1 = values1 + values2</weak_warning>
 
 
 #def expand(values1, values2):
index 1ceeece3601fcf58048a1d4e162692cacf475d25..4f4d6818fdeac17dce951665d183510c0647be3f 100644 (file)
@@ -1145,6 +1145,14 @@ public class PyTypeTest extends PyTestCase {
            "expr = f\n");
   }
 
+  // PY-20833
+  public void testStructuralTypeWithDunderLen() {
+    doTest("{__len__}",
+           "def expand(values1):\n" +
+           "    a = len(values1)\n" +
+           "    expr = values1\n");
+  }
+
   // PY-16267
   public void testGenericField() {
     doTest("str",