mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-35698, PY-33565: Delete obsolete PyCallByClassInspection. Type checker inspection covers most of the cases since there is always some type inferred for cls/self.
IDEA-CR-68591 GitOrigin-RevId: fef66f2e1e4d17de50fcca248a3ddc957f3c316d
This commit is contained in:
committed by
intellij-monorepo-bot
parent
207aaa0356
commit
1e8a086708
@@ -125,7 +125,6 @@
|
||||
<localInspection language="Python" shortName="PyAugmentAssignmentInspection" suppressId="PyAugmentAssignment" bundle="messages.PyPsiBundle" key="INSP.NAME.augment.assignment" groupKey="INSP.GROUP.python" enabledByDefault="false" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PyAugmentAssignmentInspection"/>
|
||||
<localInspection language="Python" shortName="PyBroadExceptionInspection" suppressId="PyBroadException" bundle="messages.PyPsiBundle" key="INSP.NAME.too.broad.exception.clauses" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PyBroadExceptionInspection"/>
|
||||
<localInspection language="Python" shortName="PyByteLiteralInspection" suppressId="PyByteLiteral" bundle="messages.PyPsiBundle" key="INSP.NAME.byte.literal" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyByteLiteralInspection"/>
|
||||
<localInspection language="Python" shortName="PyCallByClassInspection" suppressId="PyCallByClass" bundle="messages.PyPsiBundle" key="INSP.NAME.different.class.call" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PyCallByClassInspection"/>
|
||||
<localInspection language="Python" shortName="PyCallingNonCallableInspection" suppressId="PyCallingNonCallable" bundle="messages.PyPsiBundle" key="INSP.NAME.calling.non.callable" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyCallingNonCallableInspection"/>
|
||||
<localInspection language="Python" shortName="PyComparisonWithNoneInspection" suppressId="PyComparisonWithNone" bundle="messages.PyPsiBundle" key="INSP.NAME.comparison.with.none" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PyComparisonWithNoneInspection"/>
|
||||
<localInspection language="Python" shortName="PyDataclassInspection" suppressId="PyDataclass" bundle="messages.PyPsiBundle" key="INSP.NAME.dataclass.definition.and.usages" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyDataclassInspection"/>
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection checks for calls of a method by class while passing an instance of a different class
|
||||
as <code>self</code> parameter:
|
||||
<pre>
|
||||
foo = Foo()
|
||||
Bar.baz(foo, *more)
|
||||
</pre>
|
||||
Sometimes this may be intentional and correct.
|
||||
But when unintentional, this leads to subtle bugs.
|
||||
</body>
|
||||
</html>
|
||||
@@ -808,11 +808,6 @@ INSP.async.call=Coroutine is not awaited
|
||||
INSP.NAME.attribute.outside.init=Instance attribute defined outside __init__
|
||||
INSP.attribute.outside.init=Instance attribute {0} defined outside __init__
|
||||
|
||||
# PyCallByClassInspection
|
||||
INSP.NAME.different.class.call=Calling a method by class using an instance of a different class
|
||||
INSP.different.class.call.instance.of.class.expected.not.class.itself=An instance of {0} expected, not the class itself
|
||||
INSP.different.class.call.passing.class.instead.class=Passing {0} instead of {1}. Is this intentional?
|
||||
|
||||
# PyMissingOrEmptyDocstringInspection
|
||||
INSP.NAME.missing.or.empty.docstring=Missing or empty docstring
|
||||
INSP.no.docstring=Missing docstring
|
||||
|
||||
-132
@@ -1,132 +0,0 @@
|
||||
// Copyright 2000-2017 JetBrains s.r.o.
|
||||
// Use of this source code is governed by the Apache 2.0 license that can be
|
||||
// found in the LICENSE file.
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel;
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.PyPsiBundle;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.types.PyCallableParameter;
|
||||
import com.jetbrains.python.psi.types.PyCallableType;
|
||||
import com.jetbrains.python.psi.types.PyClassType;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.jetbrains.python.psi.PyFunction.Modifier.CLASSMETHOD;
|
||||
import static com.jetbrains.python.psi.PyFunction.Modifier.STATICMETHOD;
|
||||
|
||||
/**
|
||||
* Checks for for calls like {@code X.method(y,...)}, where y is not an instance of X.
|
||||
* <br/>
|
||||
* Not marked are cases of inheritance calls in old-style classes, like:<pre>
|
||||
* class B(A):
|
||||
* def foo(self):
|
||||
* A.foo(self)
|
||||
* </pre>
|
||||
* <br/>
|
||||
* User: dcheryasov
|
||||
*/
|
||||
public class PyCallByClassInspection extends PyInspection {
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public HighlightDisplayLevel getDefaultLevel() {
|
||||
return HighlightDisplayLevel.WEAK_WARNING;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly, @NotNull LocalInspectionToolSession session) {
|
||||
return new Visitor(holder, session);
|
||||
}
|
||||
|
||||
public static class Visitor extends PyInspectionVisitor {
|
||||
|
||||
public Visitor(final ProblemsHolder holder, LocalInspectionToolSession session) {
|
||||
super(holder, session);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visitPyCallExpression(@NotNull PyCallExpression call) {
|
||||
PyExpression callee = call.getCallee();
|
||||
if (callee instanceof PyQualifiedExpression) {
|
||||
PyExpression qualifier = ((PyQualifiedExpression)callee).getQualifier();
|
||||
if (qualifier != null) {
|
||||
PyType qual_type = myTypeEvalContext.getType(qualifier);
|
||||
if (qual_type instanceof PyClassType) {
|
||||
final PyClassType qual_class_type = (PyClassType)qual_type;
|
||||
if (qual_class_type.isDefinition()) {
|
||||
PyClass qual_class = qual_class_type.getPyClass();
|
||||
final PyCallExpression.PyArgumentsMapping mapping = ContainerUtil.getFirstItem(call.multiMapArguments(getResolveContext()));
|
||||
final PyCallableType callableType = mapping == null ? null : mapping.getCallableType();
|
||||
if (callableType != null && callableType.getModifier() != STATICMETHOD) {
|
||||
final PyCallableParameter firstParameter =
|
||||
ContainerUtil.getFirstItem(callableType.getParameters(myTypeEvalContext));
|
||||
if (firstParameter != null) {
|
||||
for (Map.Entry<PyExpression, PyCallableParameter> entry : mapping.getMappedParameters().entrySet()) {
|
||||
// we ignore *arg and **arg which we cannot analyze
|
||||
if (firstParameter.equals(entry.getValue())) {
|
||||
PyExpression first_arg = entry.getKey();
|
||||
assert first_arg != null;
|
||||
PyType first_arg_type = myTypeEvalContext.getType(first_arg);
|
||||
if (first_arg_type instanceof PyClassType) {
|
||||
final PyClassType first_arg_class_type = (PyClassType)first_arg_type;
|
||||
if (first_arg_class_type.isDefinition() && callableType.getModifier() != CLASSMETHOD) {
|
||||
registerProblem(
|
||||
first_arg,
|
||||
PyPsiBundle.message("INSP.different.class.call.instance.of.class.expected.not.class.itself", qual_class.getQualifiedName())
|
||||
);
|
||||
}
|
||||
PyClass first_arg_class = first_arg_class_type.getPyClass();
|
||||
if (first_arg_class != qual_class) {
|
||||
// delegating to a parent is fine
|
||||
if (callableType.getCallable() instanceof PyFunction) {
|
||||
PyCallable callable = PsiTreeUtil.getParentOfType(call, PyCallable.class);
|
||||
if (callable != null) {
|
||||
PyFunction method = callable.asMethod();
|
||||
if (method != null) {
|
||||
PyClass calling_class = method.getContainingClass();
|
||||
assert calling_class != null; // it's a method
|
||||
if (first_arg_class.isSubclass(qual_class, myTypeEvalContext) &&
|
||||
calling_class.isSubclass(qual_class, myTypeEvalContext)) {
|
||||
break;
|
||||
// TODO: might propose to switch to super() here
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// otherwise, it's not
|
||||
registerProblem(
|
||||
first_arg,
|
||||
PyPsiBundle.message(
|
||||
"INSP.different.class.call.passing.class.instead.class",
|
||||
first_arg_class.getQualifiedName(), qual_class.getQualifiedName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
break; // once we found the first parameter, we don't need the rest
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
class Z(object):
|
||||
def method(self):
|
||||
pass
|
||||
|
||||
class A(object):
|
||||
def method(self, *args, **kwargs):
|
||||
Z.method(<weak_warning descr="Passing inspections.PyCallByClassInspection.test.A instead of inspections.PyCallByClassInspection.test.Z. Is this intentional?">self</weak_warning>) # passing wrong instance
|
||||
Z.method(<weak_warning descr="An instance of inspections.PyCallByClassInspection.test.Z expected, not the class itself">Z</weak_warning>) # passing class instead of instance
|
||||
Z.method(<weak_warning descr="Passing inspections.PyCallByClassInspection.test.A instead of inspections.PyCallByClassInspection.test.Z. Is this intentional?"><weak_warning descr="An instance of inspections.PyCallByClassInspection.test.Z expected, not the class itself">A</weak_warning></weak_warning>) # passing class instead of instance AND wrong class
|
||||
Z.method(Z()) #pass
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
class B(A):
|
||||
def __init__(self):
|
||||
A.__init__(self) # pass
|
||||
|
||||
A.method(<weak_warning descr="Passing inspections.PyCallByClassInspection.test.B instead of inspections.PyCallByClassInspection.test.A. Is this intentional?">B()</weak_warning>)
|
||||
|
||||
|
||||
# PY-21083
|
||||
float.fromhex('A')
|
||||
@@ -0,0 +1,19 @@
|
||||
class Z:
|
||||
def method(self):
|
||||
pass
|
||||
|
||||
class A:
|
||||
def method(self):
|
||||
Z.method(<warning descr="Expected type 'Z', got 'A' instead">self</warning>) # passing wrong instance
|
||||
Z.method(<warning descr="Expected type 'Z', got 'Type[Z]' instead">Z</warning>) # passing class instead of instance
|
||||
Z.method(<warning descr="Expected type 'Z', got 'Type[A]' instead">A</warning>) # passing class instead of instance AND wrong class
|
||||
Z.method(Z()) #pass
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
class B(A):
|
||||
def __init__(self):
|
||||
A.__init__(self) # pass
|
||||
|
||||
A.method(B())
|
||||
@@ -4,7 +4,6 @@ package com.jetbrains.python;
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
|
||||
import com.jetbrains.python.inspections.PyNonAsciiCharInspection;
|
||||
import com.jetbrains.python.documentation.docstrings.DocStringFormat;
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
import com.jetbrains.python.inspections.*;
|
||||
@@ -159,10 +158,6 @@ public class PythonInspectionsTest extends PyTestCase {
|
||||
myFixture.checkHighlighting(true, false, true);
|
||||
}
|
||||
|
||||
public void testPyCallByClassInspection() {
|
||||
doHighlightingTest(PyCallByClassInspection.class); // ok, we can handle insanely long lines :)
|
||||
}
|
||||
|
||||
private void doHighlightingTest(final Class<? extends PyInspection> inspectionClass) {
|
||||
myFixture.configureByFile("inspections/" + getTestName(false) + "/test.py");
|
||||
myFixture.enableInspections(inspectionClass);
|
||||
|
||||
@@ -1255,4 +1255,8 @@ public class PyTypeCheckerInspectionTest extends PyInspectionTestCase {
|
||||
"func(42, <warning descr=\"Expected type '(int) -> None' (matched generic type '(T) -> None'), got '(x: str) -> None' instead\">accepts_anything</warning>)")
|
||||
);
|
||||
}
|
||||
|
||||
public void testCallByClass() {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user