mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-76859 Report a warning if a class being constructed does not match __init__ method's self parameter type
GitOrigin-RevId: ba64f70594968e4e2981e590d0f0c3d00003f7da
This commit is contained in:
committed by
intellij-monorepo-bot
parent
046cafe8b4
commit
765735660d
+22
-8
@@ -421,7 +421,7 @@ public class PyTypeCheckerInspection extends PyInspection {
|
||||
.nonNull()
|
||||
.toList();
|
||||
|
||||
if (!matchedCalleeResultsExist(calleesResults)) {
|
||||
if (!ContainerUtil.exists(calleesResults, calleeResults -> isMatched(calleeResults))) {
|
||||
PyTypeCheckerInspectionProblemRegistrar
|
||||
.registerProblem(this, callSite, getArgumentTypes(calleesResults), calleesResults, myTypeEvalContext);
|
||||
}
|
||||
@@ -472,6 +472,22 @@ public class PyTypeCheckerInspection extends PyInspection {
|
||||
|
||||
final var receiver = callSite.getReceiver(callableType.getCallable());
|
||||
final var substitutions = PyTypeChecker.unifyReceiver(receiver, myTypeEvalContext);
|
||||
|
||||
// When a constructor call resolves to `__init__` method,
|
||||
// match the class being constructed against the type of `self` parameter.
|
||||
if (PyUtil.isInitMethod(callableType.getCallable()) &&
|
||||
receiver != null &&
|
||||
myTypeEvalContext.getType(receiver) instanceof PyClassType receiverType &&
|
||||
receiverType.isDefinition()) {
|
||||
PyCallableParameter selfParameter = ContainerUtil.getFirstItem(mapping.getImplicitParameters());
|
||||
if (selfParameter != null) {
|
||||
final PyType actual = receiverType.toInstance();
|
||||
final PyType expected = selfParameter.getArgumentType(myTypeEvalContext);
|
||||
final boolean matched = matchParameterAndArgument(expected, actual, receiver, substitutions);
|
||||
result.add(new AnalyzeArgumentResult(receiver, expected, substituteGenerics(expected, substitutions), actual, matched));
|
||||
}
|
||||
}
|
||||
|
||||
final var mappedParameters = mapping.getMappedParameters();
|
||||
final var regularMappedParameters = getRegularMappedParameters(mappedParameters);
|
||||
|
||||
@@ -668,13 +684,11 @@ public class PyTypeCheckerInspection extends PyInspection {
|
||||
: null;
|
||||
}
|
||||
|
||||
private static boolean matchedCalleeResultsExist(@NotNull List<AnalyzeCalleeResults> calleesResults) {
|
||||
return ContainerUtil.exists(calleesResults, calleeResults ->
|
||||
ContainerUtil.all(calleeResults.getResults(), AnalyzeArgumentResult::isMatched) &&
|
||||
calleeResults.getUnmatchedArguments().isEmpty() &&
|
||||
calleeResults.getUnmatchedParameters().isEmpty() &&
|
||||
calleeResults.getUnfilledPositionalVarargs().isEmpty()
|
||||
);
|
||||
private static boolean isMatched(@NotNull AnalyzeCalleeResults calleeResults) {
|
||||
return ContainerUtil.all(calleeResults.getResults(), AnalyzeArgumentResult::isMatched) &&
|
||||
calleeResults.getUnmatchedArguments().isEmpty() &&
|
||||
calleeResults.getUnmatchedParameters().isEmpty() &&
|
||||
calleeResults.getUnfilledPositionalVarargs().isEmpty();
|
||||
}
|
||||
|
||||
private static @NotNull List<PyType> getArgumentTypes(@NotNull List<AnalyzeCalleeResults> calleesResults) {
|
||||
|
||||
@@ -1680,6 +1680,17 @@ public class Py3TypeCheckerInspectionTest extends PyInspectionTestCase {
|
||||
subClass.foo(subClass.foo(<warning descr="Expected type 'SubClass' (matched generic type 'Self@MyClass'), got 'MyClass' instead">myClass</warning>))""");
|
||||
}
|
||||
|
||||
public void testSelfParameterType() {
|
||||
doTestByText("""
|
||||
class MyClass[T]:
|
||||
def __init__(self: "MyClass[int]") -> None: ...
|
||||
|
||||
MyClass()
|
||||
MyClass[int]()
|
||||
<warning descr="Expected type 'MyClass[int]', got 'MyClass[str]' instead">MyClass[str]</warning>()
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-53104
|
||||
public void testProtocolSelfClass() {
|
||||
doTestByText("""
|
||||
|
||||
Reference in New Issue
Block a user