From e314e71e3cae14798f9ededc62763621a8fc30c8 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Tue, 15 Oct 2024 16:25:05 +0300 Subject: [PATCH] PY-42137 Report incorrect arguments if no overload matches Previously, we reported call arguments only if either all callee candidates have unmatched arguments or all call candidates have unmatched parameters. When there was a mix of the two, we reported nothing. GitOrigin-RevId: 97b42faf10de74ee7cd10f934d9eb94e1c8bbb34 --- .../resources/messages/PyPsiBundle.properties | 1 + .../inspections/PyArgumentListInspection.java | 30 +++++++++++++++---- ...tionsHaveBothTooFewAndTooManyParameters.py | 8 +++++ ...loadsHaveBothTooFewAndTooManyParameters.py | 17 +++++++++++ .../Py3ArgumentListInspectionTest.java | 10 +++++++ 5 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 python/testData/inspections/PyArgumentListInspection/mismatchedConditionalImplementationsHaveBothTooFewAndTooManyParameters.py create mode 100644 python/testData/inspections/PyArgumentListInspection/mismatchedOverloadsHaveBothTooFewAndTooManyParameters.py diff --git a/python/python-psi-impl/resources/messages/PyPsiBundle.properties b/python/python-psi-impl/resources/messages/PyPsiBundle.properties index 38f8fa532027..3529c708d02d 100644 --- a/python/python-psi-impl/resources/messages/PyPsiBundle.properties +++ b/python/python-psi-impl/resources/messages/PyPsiBundle.properties @@ -552,6 +552,7 @@ INSP.unexpected.arg=Unexpected argument INSP.unexpected.arg(s)=Unexpected argument(s) INSP.parameter.unfilled=Parameter ''{0}'' unfilled INSP.parameter(s).unfilled=Parameter(s) unfilled +INSP.incorrect.arguments=Incorrect argument(s) INSP.possible.callees=Possible callees INSP.function.lacks.positional.argument=Function ''{0}'' lacks a positional argument INSP.expected.dict.got.type=Expected a dictionary, got {0} diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyArgumentListInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyArgumentListInspection.java index 8633e675afea..c5921f95790f 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyArgumentListInspection.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyArgumentListInspection.java @@ -122,8 +122,20 @@ public final class PyArgumentListInspection extends PyInspection { } } - highlightUnexpectedArguments(node, holder, mappings, context); - highlightUnfilledParameters(node, holder, mappings, context); + if (!mappings.isEmpty()) { + boolean specificMismatchKindReported = false; + if (ContainerUtil.all(mappings, mapping -> !mapping.getUnmappedArguments().isEmpty())) { + highlightUnexpectedArguments(node, holder, mappings, context); + specificMismatchKindReported = true; + } + if (ContainerUtil.all(mappings, mapping -> !mapping.getUnmappedParameters().isEmpty())) { + highlightUnfilledParameters(node, holder, mappings, context); + specificMismatchKindReported = true; + } + if (!specificMismatchKindReported && ContainerUtil.all(mappings, mapping -> !mapping.isComplete())) { + highlightIncorrectArguments(node, holder, mappings, context); + } + } highlightStarArgumentTypeMismatch(node, holder, context); } @@ -224,8 +236,6 @@ public final class PyArgumentListInspection extends PyInspection { @NotNull ProblemsHolder holder, @NotNull List mappings, @NotNull TypeEvalContext context) { - if (mappings.isEmpty() || mappings.stream().anyMatch(mapping -> mapping.getUnmappedArguments().isEmpty())) return; - if (mappings.size() == 1) { // if there is only one mapping, we could suggest quick fixes final Set duplicateKeywords = getDuplicateKeywordArguments(node); @@ -270,8 +280,6 @@ public final class PyArgumentListInspection extends PyInspection { @NotNull ProblemsHolder holder, @NotNull List mappings, @NotNull TypeEvalContext context) { - if (mappings.isEmpty() || mappings.stream().anyMatch(mapping -> mapping.getUnmappedParameters().isEmpty())) return; - Optional .ofNullable(node.getNode()) .map(astNode -> astNode.findChildByType(PyTokenTypes.RPAR)) @@ -296,6 +304,16 @@ public final class PyArgumentListInspection extends PyInspection { ); } + private static void highlightIncorrectArguments(@NotNull PyArgumentList node, + @NotNull ProblemsHolder holder, + @NotNull List mappings, + @NotNull TypeEvalContext context) { + holder.registerProblem( + node, + addPossibleCalleesRepresentation(PyPsiBundle.message("INSP.incorrect.arguments"), mappings, context, holder.isOnTheFly()) + ); + } + @NlsSafe @NotNull private static String addPossibleCalleesRepresentation(@NotNull @InspectionMessage String prefix, diff --git a/python/testData/inspections/PyArgumentListInspection/mismatchedConditionalImplementationsHaveBothTooFewAndTooManyParameters.py b/python/testData/inspections/PyArgumentListInspection/mismatchedConditionalImplementationsHaveBothTooFewAndTooManyParameters.py new file mode 100644 index 000000000000..79792d33acbc --- /dev/null +++ b/python/testData/inspections/PyArgumentListInspection/mismatchedConditionalImplementationsHaveBothTooFewAndTooManyParameters.py @@ -0,0 +1,8 @@ +if undefined: + def f(x): + pass +else: + def f(x, y, z): + pass + +f(1, 2) \ No newline at end of file diff --git a/python/testData/inspections/PyArgumentListInspection/mismatchedOverloadsHaveBothTooFewAndTooManyParameters.py b/python/testData/inspections/PyArgumentListInspection/mismatchedOverloadsHaveBothTooFewAndTooManyParameters.py new file mode 100644 index 000000000000..9a1a3cd96d7a --- /dev/null +++ b/python/testData/inspections/PyArgumentListInspection/mismatchedOverloadsHaveBothTooFewAndTooManyParameters.py @@ -0,0 +1,17 @@ +from typing import overload, Optional + +@overload +def mouse_event(x1: int, y1: int) -> None: ... +@overload +def mouse_event(x1: int, y1: int, x2: int, y2: int, y3: int) -> None: ... + +def mouse_event(x1: int, y1: int, x2: Optional[int] = None, y2: Optional[int] = None, y3: Optional[int] = None) -> int: + pass + + +mouse_event(1) # Parameters unfilled +mouse_event(1, 2) # OK +mouse_event(1, 2, 3) # OK (it shouldn't be) +mouse_event(1, 2, 3, 4) # OK (it shouldn't be) +mouse_event(1, 2, 3, 4, 5) # OK +mouse_event(1, 2, 3, 4, 5, 6) # Unexpected argument(s) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3ArgumentListInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3ArgumentListInspectionTest.java index 10283e9ae6b3..b8985da994be 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3ArgumentListInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3ArgumentListInspectionTest.java @@ -366,4 +366,14 @@ public class Py3ArgumentListInspectionTest extends PyInspectionTestCase { public void testInitByDataclassTransformOnMetaClass() { doMultiFileTest(); } + + // PY-42137 + public void testMismatchedOverloadsHaveBothTooFewAndTooManyParameters() { + doTest(); + } + + // PY-42137 + public void testMismatchedConditionalImplementationsHaveBothTooFewAndTooManyParameters() { + doTest(); + } }