From 19f5047bab15dd4b791da6b2703588a5997e9a66 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 14 Aug 2012 15:07:58 +0400 Subject: [PATCH 1/6] Removed obsolete not null checks --- .../python/psi/types/PyClassTypeImpl.java | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index 8f0530c079f1..8626533ad1c2 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -111,9 +111,6 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { @Nullable PyExpression location, @NotNull AccessDirection direction, @NotNull PyResolveContext resolveContext) { - if (myClass == null) { - return null; - } if (resolveContext.allowProperties()) { Property property = myClass.findProperty(name); if (property != null) { @@ -141,14 +138,12 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { PyType first_arg_type = first_arg.getType(resolveContext.getTypeEvalContext()); if (first_arg_type instanceof PyClassType) { PyClass derived_class = ((PyClassType)first_arg_type).getPyClass(); - if (derived_class != null) { - final Iterator base_it = derived_class.iterateAncestorClasses().iterator(); - if (base_it.hasNext()) { - return new PyClassTypeImpl(base_it.next(), true).resolveMember(name, location, direction, resolveContext); - } - else { - return null; // no base classes = super() cannot proxy anything meaningful from a base class - } + final Iterator base_it = derived_class.iterateAncestorClasses().iterator(); + if (base_it.hasNext()) { + return new PyClassTypeImpl(base_it.next(), true).resolveMember(name, location, direction, resolveContext); + } + else { + return null; // no base classes = super() cannot proxy anything meaningful from a base class } } } From a35bac71b0591746f0a02567e028aed8d3206e99 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 14 Aug 2012 15:36:21 +0400 Subject: [PATCH 2/6] Removed unnecessary check that forced switch from stubs to AST --- .../python/debugger/PyCallSignatureTypeProvider.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/python/src/com/jetbrains/python/debugger/PyCallSignatureTypeProvider.java b/python/src/com/jetbrains/python/debugger/PyCallSignatureTypeProvider.java index 27e254986903..1afe7902ce43 100644 --- a/python/src/com/jetbrains/python/debugger/PyCallSignatureTypeProvider.java +++ b/python/src/com/jetbrains/python/debugger/PyCallSignatureTypeProvider.java @@ -2,16 +2,17 @@ package com.jetbrains.python.debugger; import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.psi.PyNamedParameter; -import com.jetbrains.python.psi.PyParameterList; import com.jetbrains.python.psi.impl.PyWeakTypeFactory; -import com.jetbrains.python.psi.types.*; +import com.jetbrains.python.psi.types.PyType; +import com.jetbrains.python.psi.types.PyTypeParser; +import com.jetbrains.python.psi.types.PyTypeProviderBase; +import com.jetbrains.python.psi.types.TypeEvalContext; /** * @author traff */ public class PyCallSignatureTypeProvider extends PyTypeProviderBase { public PyType getParameterType(final PyNamedParameter param, final PyFunction func, TypeEvalContext context) { - if (!(param.getParent() instanceof PyParameterList)) return null; String type = ((PySignatureCacheManagerImpl)PySignatureCacheManager.getInstance(param.getProject())).findParameterType(param); if (type != null) { PyType typeByName = PyTypeParser.getTypeByName(param, type); From b5fc1dbd571058eb737d8ab00aebef36919305d4 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 14 Aug 2012 15:45:11 +0400 Subject: [PATCH 3/6] Refactored call signature provider in order not to switch from stubs to AST --- .../debugger/PyCallSignatureTypeProvider.java | 17 ++++++++++------- .../debugger/PySignatureCacheManagerImpl.java | 13 ++++--------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/python/src/com/jetbrains/python/debugger/PyCallSignatureTypeProvider.java b/python/src/com/jetbrains/python/debugger/PyCallSignatureTypeProvider.java index 1afe7902ce43..750edbb342b2 100644 --- a/python/src/com/jetbrains/python/debugger/PyCallSignatureTypeProvider.java +++ b/python/src/com/jetbrains/python/debugger/PyCallSignatureTypeProvider.java @@ -7,22 +7,25 @@ import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.PyTypeParser; import com.jetbrains.python.psi.types.PyTypeProviderBase; import com.jetbrains.python.psi.types.TypeEvalContext; +import org.jetbrains.annotations.Nullable; /** * @author traff */ public class PyCallSignatureTypeProvider extends PyTypeProviderBase { public PyType getParameterType(final PyNamedParameter param, final PyFunction func, TypeEvalContext context) { - String type = ((PySignatureCacheManagerImpl)PySignatureCacheManager.getInstance(param.getProject())).findParameterType(param); - if (type != null) { - PyType typeByName = PyTypeParser.getTypeByName(param, type); - return buildWeakType(typeByName); - } - else { - return null; + final String name = param.getName(); + if (name != null) { + final String type = ((PySignatureCacheManagerImpl)PySignatureCacheManager.getInstance(param.getProject())).findParameterType(func, name); + if (type != null) { + final PyType typeByName = PyTypeParser.getTypeByName(param, type); + return buildWeakType(typeByName); + } } + return null; } + @Nullable private static PyType buildWeakType(PyType type) { return PyWeakTypeFactory.create(type); } diff --git a/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java b/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java index dd65ea7f96f9..009811ab0b2d 100644 --- a/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java +++ b/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java @@ -9,11 +9,9 @@ import com.intellij.openapi.vfs.newvfs.FileAttribute; import com.intellij.psi.PsiFile; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.ProjectScopeBuilder; -import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.django.util.VirtualFileUtil; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; -import com.jetbrains.python.psi.PyNamedParameter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -103,13 +101,10 @@ public class PySignatureCacheManagerImpl extends PySignatureCacheManager { } @Nullable - public static String findParameterType(@NotNull PyNamedParameter parameter) { - PyFunction function = PsiTreeUtil.getParentOfType(parameter, PyFunction.class); - if (function != null) { - PySignature signature = findSignature(function); - if (signature != null) { - return signature.getArgType(parameter.getName()); - } + public static String findParameterType(@NotNull PyFunction function, @NotNull String name) { + final PySignature signature = findSignature(function); + if (signature != null) { + return signature.getArgType(name); } return null; } From 5b77e35033331902080766394951e9fb352839af Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 14 Aug 2012 16:07:05 +0400 Subject: [PATCH 4/6] Disabled type checker for operators that are assigned, not defined via functions (PY-6925) --- .../python/psi/types/PyTypeChecker.java | 37 ++++++++++--------- .../AssignedOperator.py | 8 ++++ .../PyTypeCheckerInspectionTest.java | 5 +++ 3 files changed, 32 insertions(+), 18 deletions(-) create mode 100644 python/testData/inspections/PyTypeCheckerInspection/AssignedOperator.py diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 03af7858b806..500046cb6ae0 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -323,24 +323,25 @@ public class PyTypeChecker { if (resolved instanceof PyTypedElement) { final PyTypedElement typedElement = (PyTypedElement)resolved; final PyType type = typedElement.getType(context); - if (type instanceof PyFunctionType) { - final PyFunction function = ((PyFunctionType)type).getFunction(); - final boolean isRight = PyNames.isRightOperatorName(typedElement.getName()); - final PyExpression arg = isRight ? expr.getLeftExpression() : expr.getRightExpression(); - final PyExpression receiver = isRight ? expr.getRightExpression() : expr.getLeftExpression(); - final PyParameter[] parameters = function.getParameterList().getParameters(); - if (parameters.length >= 2) { - final PyNamedParameter param = parameters[1].getAsNamed(); - if (arg != null && param != null) { - final Map arguments = new LinkedHashMap(); - arguments.put(arg, param); - final AnalyzeCallResults results = new AnalyzeCallResults(function, receiver, arguments); - if (firstResults == null) { - firstResults = results; - } - if (match(param.getType(context), arg.getType(context), context)) { - return results; - } + if (!(type instanceof PyFunctionType)) { + return null; + } + final PyFunction function = ((PyFunctionType)type).getFunction(); + final boolean isRight = PyNames.isRightOperatorName(typedElement.getName()); + final PyExpression arg = isRight ? expr.getLeftExpression() : expr.getRightExpression(); + final PyExpression receiver = isRight ? expr.getRightExpression() : expr.getLeftExpression(); + final PyParameter[] parameters = function.getParameterList().getParameters(); + if (parameters.length >= 2) { + final PyNamedParameter param = parameters[1].getAsNamed(); + if (arg != null && param != null) { + final Map arguments = new LinkedHashMap(); + arguments.put(arg, param); + final AnalyzeCallResults results = new AnalyzeCallResults(function, receiver, arguments); + if (firstResults == null) { + firstResults = results; + } + if (match(param.getType(context), arg.getType(context), context)) { + return results; } } } diff --git a/python/testData/inspections/PyTypeCheckerInspection/AssignedOperator.py b/python/testData/inspections/PyTypeCheckerInspection/AssignedOperator.py new file mode 100644 index 000000000000..d5edd3dc8440 --- /dev/null +++ b/python/testData/inspections/PyTypeCheckerInspection/AssignedOperator.py @@ -0,0 +1,8 @@ +def f(x): + return x + +class C(object): + __div__, __rdiv__ = f(0) + +c = C() +print(c / 2) diff --git a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java index 7bf8bc23d398..0169210658f1 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java @@ -135,4 +135,9 @@ public class PyTypeCheckerInspectionTest extends PyTestCase { public void testDecoratedFunction() { doTest(); } + + // PY-6925 + public void testAssignedOperator() { + doTest(); + } } From bcc92a856cf988f3fabea0b7da40c0ed5ca5e0bc Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 14 Aug 2012 17:30:18 +0400 Subject: [PATCH 5/6] Fixed false positive in unused locals for 'while' loops with interrupted control flow at the end (PY-7072) --- .../codeInsight/controlflow/PyControlFlowBuilder.java | 5 +++-- .../inspections/PyUnusedLocalVariableInspection/test.py | 8 ++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java b/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java index 8bc80feaa473..6b53a9eaa80a 100644 --- a/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java +++ b/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java @@ -334,8 +334,9 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor { if (list != null) { myBuilder.startConditionalNode(list, condition, true); list.accept(this); - if (myBuilder.prevInstruction != null) { - myBuilder.addEdge(myBuilder.prevInstruction, instruction); //loop + final Instruction prevInstruction = myBuilder.prevInstruction != null ? myBuilder.prevInstruction : getPrevInstruction(list); + if (prevInstruction != null) { + myBuilder.addEdge(prevInstruction, instruction); //loop } } myBuilder.prevInstruction = head; diff --git a/python/testData/inspections/PyUnusedLocalVariableInspection/test.py b/python/testData/inspections/PyUnusedLocalVariableInspection/test.py index ec747ac101f2..345b4ce18440 100644 --- a/python/testData/inspections/PyUnusedLocalVariableInspection/test.py +++ b/python/testData/inspections/PyUnusedLocalVariableInspection/test.py @@ -286,3 +286,11 @@ class C: # PY-7126 def test_unused_empty_function(x): pass + + +# PY-7072 +def test_unused_variable_in_cycle(x, c): + while x > 0: + x -= 1 #pass + if c: + break From 346ea963ea45383991cdb9b3f38c665a08919e35 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 14 Aug 2012 18:09:55 +0400 Subject: [PATCH 6/6] Fixed updating skeletons for old-style module names 'foomodule.so' for 'foo' (PY-7132) --- python/helpers/generator3.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index f71d077e7c65..6a3be8d504fd 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -2244,6 +2244,10 @@ def cut_binary_lib_suffix(path, f): m = BIN_MODULE_FNAME_PAT.match(f) if m: ret = m.group(1) + modlen = len('module') + retlen = len(ret) + if ret.endswith('module') and retlen > modlen and f.endswith('.so'): + ret = ret[:(retlen - modlen)] if f.endswith('.pyc') or f.endswith('.pyo'): fullname = os.path.join(path, f[:-1]) # check for __pycache__ is made outside if os.path.exists(fullname):