mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
[PY-33917] Now '__init_subclass__' is treated as and constructor-like method in appropriate cases
GitOrigin-RevId: c2ac58960f641868006141ae3001c932c6a8eaaf
This commit is contained in:
committed by
intellij-monorepo-bot
parent
ac7fd43a32
commit
b076ea2794
@@ -41,7 +41,7 @@ public interface PyAstCallExpression extends PyAstCallSiteExpression {
|
||||
|
||||
@Contract("null -> false")
|
||||
private static boolean isImplicitlyInvokedMethod(@Nullable PyAstCallable resolvedCallee) {
|
||||
if (PyUtilCore.isInitOrNewMethod(resolvedCallee)) return true;
|
||||
if (PyUtilCore.isConstructorLikeMethod(resolvedCallee)) return true;
|
||||
|
||||
if (resolvedCallee instanceof PyAstFunction function) {
|
||||
return PyNames.CALL.equals(function.getName()) && function.getContainingClass() != null;
|
||||
|
||||
@@ -191,7 +191,26 @@ public final class PyUtilCore {
|
||||
if (function == null) return false;
|
||||
|
||||
final String name = function.getName();
|
||||
return (PyNames.INIT.equals(name) || PyNames.NEW.equals(name)) && function.getContainingClass() != null;
|
||||
return (PyNames.INIT.equals(name) ||
|
||||
PyNames.NEW.equals(name)) && function.getContainingClass() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if passed {@code element} is a method (this means a function inside a class) named {@code __init__},
|
||||
* {@code __init_subclass__}, or {@code __new__}.
|
||||
* @see PyUtil#isInitMethod(PsiElement)
|
||||
* @see PyUtil#isNewMethod(PsiElement)
|
||||
* @see PyUtil#turnConstructorIntoClass(PyFunction)
|
||||
*/
|
||||
@Contract("null -> false")
|
||||
public static boolean isConstructorLikeMethod(@Nullable PsiElement element) {
|
||||
final PyAstFunction function = ObjectUtils.tryCast(element, PyAstFunction.class);
|
||||
if (function == null) return false;
|
||||
|
||||
final String name = function.getName();
|
||||
return (PyNames.INIT_SUBCLASS.equals(name) ||
|
||||
PyNames.INIT.equals(name) ||
|
||||
PyNames.NEW.equals(name)) && function.getContainingClass() != null;
|
||||
}
|
||||
|
||||
public static boolean isStringLiteral(@Nullable PyAstStatement stmt) {
|
||||
|
||||
@@ -187,7 +187,7 @@ public final class PyCompatibilityInspection extends PyInspection {
|
||||
if (resolvedCallee instanceof PyFunction function) {
|
||||
final PyClass containingClass = function.getContainingClass();
|
||||
|
||||
final String functionName = PyUtil.isInitOrNewMethod(function) ? callee.getText() : function.getName();
|
||||
final String functionName = PyUtil.isConstructorLikeMethod(function) ? callee.getText() : function.getName();
|
||||
|
||||
if (containingClass != null) {
|
||||
final String className = containingClass.getName();
|
||||
|
||||
@@ -37,7 +37,7 @@ public final class PyMethodOverridingInspection extends PyInspection {
|
||||
final PyClass cls = function.getContainingClass();
|
||||
if (cls == null) return;
|
||||
|
||||
if (PyUtil.isInitOrNewMethod(function) ||
|
||||
if (PyUtil.isConstructorLikeMethod(function) ||
|
||||
PyKnownDecoratorUtil.hasUnknownOrChangingSignatureDecorator(function, myTypeEvalContext) ||
|
||||
ContainerUtil.exists(PyInspectionExtension.EP_NAME.getExtensions(), e -> e.ignoreMethodParameters(function, myTypeEvalContext))) {
|
||||
return;
|
||||
|
||||
@@ -1482,6 +1482,18 @@ public final class PyUtil {
|
||||
public static boolean isInitOrNewMethod(@Nullable PsiElement element) {
|
||||
return PyUtilCore.isInitOrNewMethod(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if passed {@code element} is a method (this means a function inside a class) named {@code __init__},
|
||||
* {@code __init_subclass__}, or {@code __new__}.
|
||||
* @see PyUtil#isInitMethod(PsiElement)
|
||||
* @see PyUtil#isNewMethod(PsiElement)
|
||||
* @see PyUtil#turnConstructorIntoClass(PyFunction)
|
||||
*/
|
||||
@Contract("null -> false")
|
||||
public static boolean isConstructorLikeMethod(@Nullable PsiElement element) {
|
||||
return PyUtilCore.isConstructorLikeMethod(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return containing class for a method named {@code __init__} or {@code __new__}.
|
||||
|
||||
@@ -353,7 +353,7 @@ public class PyQualifiedReference extends PyReferenceImpl {
|
||||
if (pyElement == null) {
|
||||
return false;
|
||||
}
|
||||
if (Objects.equals(referencedName, pyElement.getName()) && !PyUtil.isInitOrNewMethod(element)) {
|
||||
if (Objects.equals(referencedName, pyElement.getName()) && !PyUtil.isConstructorLikeMethod(element)) {
|
||||
final PyExpression qualifier = myElement.getQualifier();
|
||||
if (qualifier != null) {
|
||||
final PyType qualifierType = resolveContext.getTypeEvalContext().getType(qualifier);
|
||||
|
||||
@@ -54,7 +54,7 @@ class PyInlineFunctionHandler : InlineActionHandler() {
|
||||
val error = when {
|
||||
element.isAsync -> PyPsiBundle.message("refactoring.inline.function.async")
|
||||
element.isGenerator -> PyPsiBundle.message("refactoring.inline.function.generator")
|
||||
PyUtil.isInitOrNewMethod(element) -> PyPsiBundle.message("refactoring.inline.function.constructor")
|
||||
PyUtil.isConstructorLikeMethod(element) -> PyPsiBundle.message("refactoring.inline.function.constructor")
|
||||
PyBuiltinCache.getInstance(element).isBuiltin(element) -> PyPsiBundle.message("refactoring.inline.function.builtin")
|
||||
isSpecialMethod(element) -> PyPsiBundle.message("refactoring.inline.function.special.method")
|
||||
isUnderSkeletonDir(element) -> PyPsiBundle.message("refactoring.inline.function.skeleton.only")
|
||||
|
||||
@@ -196,7 +196,7 @@ public final class PyDocstringGenerator {
|
||||
final RaiseVisitor visitor = new RaiseVisitor();
|
||||
final PyAstStatementList statementList = ((PyAstFunction)myDocStringOwner).getStatementList();
|
||||
statementList.accept(visitor);
|
||||
if (!PyUtilCore.isInitOrNewMethod(myDocStringOwner) && (visitor.myHasReturn || addReturn)) {
|
||||
if (!PyUtilCore.isConstructorLikeMethod(myDocStringOwner) && (visitor.myHasReturn || addReturn)) {
|
||||
// will add :return: placeholder in Sphinx/Epydoc docstrings
|
||||
withReturnValue(null);
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ public final class PyLineMarkerProvider implements LineMarkerProvider, PyLineSep
|
||||
}
|
||||
|
||||
private static @Nullable LineMarkerInfo<PsiElement> getMethodMarker(final PsiElement identifier, final PyFunction function) {
|
||||
if (PyUtil.isInitMethod(function)) {
|
||||
if (PyUtil.isConstructorLikeMethod(function)) {
|
||||
return null;
|
||||
}
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(identifier.getProject(), function.getContainingFile());
|
||||
|
||||
@@ -134,7 +134,7 @@ public class PyChangeSignatureHandler implements ChangeSignatureHandler {
|
||||
if (containingClass == null) {
|
||||
return function;
|
||||
}
|
||||
if (PyUtil.isInitOrNewMethod(function)) {
|
||||
if (PyUtil.isConstructorLikeMethod(function)) {
|
||||
return function;
|
||||
}
|
||||
final PyFunction deepestSuperMethod = PySuperMethodsSearch.findDeepestSuperMethod(function);
|
||||
|
||||
@@ -42,7 +42,7 @@ public class PyChangeSignatureUsageProcessor implements ChangeSignatureUsageProc
|
||||
if (info instanceof PyChangeInfo) {
|
||||
final PyFunction targetFunction = ((PyChangeInfo)info).getMethod();
|
||||
final List<UsageInfo> usages = PyPsiIndexUtil.findUsages(targetFunction, true);
|
||||
if (!PyUtil.isInitOrNewMethod(targetFunction)) {
|
||||
if (!PyUtil.isConstructorLikeMethod(targetFunction)) {
|
||||
final Query<PyFunction> search = PyOverridingMethodsSearch.search(targetFunction, true);
|
||||
for (PyFunction override : search.findAll()) {
|
||||
usages.add(new UsageInfo(override));
|
||||
|
||||
Reference in New Issue
Block a user