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
This commit is contained in:
Mikhail Golubev
2024-10-15 22:19:26 +00:00
committed by intellij-monorepo-bot
parent 33919a56d0
commit e314e71e3c
5 changed files with 60 additions and 6 deletions
@@ -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}
@@ -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<PyCallExpression.PyArgumentsMapping> 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<String> duplicateKeywords = getDuplicateKeywordArguments(node);
@@ -270,8 +280,6 @@ public final class PyArgumentListInspection extends PyInspection {
@NotNull ProblemsHolder holder,
@NotNull List<PyCallExpression.PyArgumentsMapping> 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<PyCallExpression.PyArgumentsMapping> 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,
@@ -0,0 +1,8 @@
if undefined:
def f(x):
pass
else:
def f(x, y, z):
pass
f<warning descr="Incorrect argument(s)Possible callees:f(x)f(x, y, z)">(1, 2)</warning>
@@ -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<warning descr="Parameter(s) unfilledPossible callees:mouse_event(x1: int, y1: int)mouse_event(x1: int, y1: int, x2: int, y2: int, y3: int)">)</warning> # Parameters unfilled
mouse_event(1, 2) # OK
mouse_event<warning descr="Incorrect argument(s)Possible callees:mouse_event(x1: int, y1: int)mouse_event(x1: int, y1: int, x2: int, y2: int, y3: int)">(1, 2, 3)</warning> # OK (it shouldn't be)
mouse_event<warning descr="Incorrect argument(s)Possible callees:mouse_event(x1: int, y1: int)mouse_event(x1: int, y1: int, x2: int, y2: int, y3: int)">(1, 2, 3, 4)</warning> # OK (it shouldn't be)
mouse_event(1, 2, 3, 4, 5) # OK
mouse_event<warning descr="Unexpected argument(s)Possible callees:mouse_event(x1: int, y1: int)mouse_event(x1: int, y1: int, x2: int, y2: int, y3: int)">(1, 2, 3, 4, 5, 6)</warning> # Unexpected argument(s)
@@ -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();
}
}