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(); + } }