From b4ac9e94d60a13fed9217085a944c124bf7dbba0 Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Wed, 21 Feb 2018 18:41:06 +0300 Subject: [PATCH] Don't analyze arguments to object method called through `super` (PY-25497) --- .../inspections/PyArgumentListInspection.java | 38 +++++++++++++++++++ .../objectMethodInPossiblyInheritanceChain.py | 23 +++++++++++ .../PyArgumentListInspectionTest.java | 5 +++ 3 files changed, 66 insertions(+) create mode 100644 python/testData/inspections/PyArgumentListInspection/objectMethodInPossiblyInheritanceChain.py diff --git a/python/src/com/jetbrains/python/inspections/PyArgumentListInspection.java b/python/src/com/jetbrains/python/inspections/PyArgumentListInspection.java index 896dd0ad086d..b7b36590bfe4 100644 --- a/python/src/com/jetbrains/python/inspections/PyArgumentListInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyArgumentListInspection.java @@ -123,6 +123,8 @@ public class PyArgumentListInspection extends PyInspection { decoratedClassInitCall(call.getCallee(), function, context)) { return; } + + if (objectMethodCallViaSuper(call, function)) return; } } } @@ -153,6 +155,42 @@ public class PyArgumentListInspection extends PyInspection { return false; } + private static boolean objectMethodCallViaSuper(@NotNull PyCallExpression call, @NotNull PyFunction function) { + /* + Class could be designed to be used in cooperative multiple inheritance + so `super()` could be resolved to some non-object class that is able to receive passed arguments. + + Example: + + class Shape(object): + def __init__(self, shapename, **kwds): + self.shapename = shapename + # in case of ColoredShape the call below will be executed on Colored + # so warning should not be raised + super(Shape, self).__init__(**kwds) + + + class Colored(object): + def __init__(self, color, **kwds): + self.color = color + super(Colored, self).__init__(**kwds) + + + class ColoredShape(Shape, Colored): + pass + */ + + final PyClass receiverClass = function.getContainingClass(); + if (receiverClass != null && PyUtil.isObjectClass(receiverClass)) { + final PyExpression receiverExpression = call.getReceiver(null); + if (receiverExpression instanceof PyCallExpression && PyUtil.isSuperCall((PyCallExpression)receiverExpression)) { + return true; + } + } + + return false; + } + private static void highlightStarArgumentTypeMismatch(PyArgumentList node, ProblemsHolder holder, TypeEvalContext context) { for (PyExpression arg : node.getArguments()) { if (arg instanceof PyStarArgument) { diff --git a/python/testData/inspections/PyArgumentListInspection/objectMethodInPossiblyInheritanceChain.py b/python/testData/inspections/PyArgumentListInspection/objectMethodInPossiblyInheritanceChain.py new file mode 100644 index 000000000000..451747aa10fe --- /dev/null +++ b/python/testData/inspections/PyArgumentListInspection/objectMethodInPossiblyInheritanceChain.py @@ -0,0 +1,23 @@ +# Class could be designed to be used in cooperative multiple inheritance +# so `super()` could be resolved to some non-object class that is able to receive passed arguments. + + +class Shape(object): + def __init__(self, shapename, **kwds): + self.shapename = shapename + # in case of ColoredShape the call below will be executed on Colored + # so warning should not be raised + super(Shape, self).__init__(**kwds) + + +class Colored(object): + def __init__(self, color, **kwds): + self.color = color + super(Colored, self).__init__(**kwds) + + +class ColoredShape(Shape, Colored): + pass + + +cs = ColoredShape(color='red', shapename='circle') diff --git a/python/testSrc/com/jetbrains/python/inspections/PyArgumentListInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyArgumentListInspectionTest.java index 5d63f2ae2e27..d46e4252b610 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyArgumentListInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyArgumentListInspectionTest.java @@ -337,4 +337,9 @@ public class PyArgumentListInspectionTest extends PyInspectionTestCase { public void testInitializingImportedTypingNamedTupleInheritor() { runWithLanguageLevel(LanguageLevel.PYTHON37, this::doMultiFileTest); } + + // PY-25497 + public void testObjectMethodInPossiblyInheritanceChain() { + doTest(); + } }