diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java index d279e5f9f999..b6116929e55e 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java @@ -140,12 +140,25 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, PyDocStrin * Since __new__ only makes sense for new-style classes, an old-style class never finds it with this method. * * @param inherited true: search in superclasses, too. - * @param context TODO: DOC + * @param context context to be used to resolve ancestors and check if this class is a new-style class * @return a method that would be called first when an instance of this class is instantiated. */ @Nullable PyFunction findInitOrNew(boolean inherited, @Nullable TypeEvalContext context); + /** + * Finds either __init__ or __new__, whichever is defined for given class, and all its overloads. + * If __init__ is defined, it is found first. This mimics the way initialization methods + * are searched for and called by Python when a constructor call is made. + * Since __new__ only makes sense for new-style classes, an old-style class never finds it with this method. + * + * @param inherited true: search in superclasses, too. + * @param context context to be used to resolve ancestors and check if this class is a new-style class + * @return a method that would be called first when an instance of this class is instantiated and all its overloads. + */ + @NotNull + List multiFindInitOrNew(boolean inherited, @Nullable TypeEvalContext context); + /** * Finds a property with the specified name in the class or one of its ancestors. * @@ -268,6 +281,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, PyDocStrin @Nullable List getOwnSlots(); + @Override @Nullable String getDocStringValue(); diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java index 31c47d433f59..e671ba8d50e6 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java @@ -130,13 +130,12 @@ public class PyCallExpressionHelper { final List ratedMarkedCallees = new ArrayList<>(); for (QualifiedRatedResolveResult resolveResult : multiResolveCallee(call.getCallee(), resolveContext)) { - final ClarifiedResolveResult clarifiedResolveResult = clarifyResolveResult(resolveResult, resolveContext); - if (clarifiedResolveResult == null) continue; + for (ClarifiedResolveResult clarifiedResolveResult : clarifyResolveResult(resolveResult, resolveContext)) { + final PyCallExpression.PyRatedMarkedCallee markedCallee = markResolveResult(clarifiedResolveResult, context, implicitOffset); + if (markedCallee == null) continue; - final PyCallExpression.PyRatedMarkedCallee markedCallee = markResolveResult(clarifiedResolveResult, context, implicitOffset); - if (markedCallee == null) continue; - - ratedMarkedCallees.add(markedCallee); + ratedMarkedCallees.add(markedCallee); + } } return forEveryScopeTakeOverloadsOtherwiseImplementations(ratedMarkedCallees, PyCallExpression.PyRatedMarkedCallee::getElement, context) @@ -187,14 +186,14 @@ public class PyCallExpressionHelper { return Collections.emptyList(); } - @Nullable - private static ClarifiedResolveResult clarifyResolveResult(@NotNull QualifiedRatedResolveResult resolveResult, - @NotNull PyResolveContext resolveContext) { + @NotNull + private static List clarifyResolveResult(@NotNull QualifiedRatedResolveResult resolveResult, + @NotNull PyResolveContext resolveContext) { final PsiElement resolved = resolveResult.getElement(); if (resolved instanceof PyClass) { - final PyFunction clarifiedResolved = ((PyClass)resolved).findInitOrNew(true, resolveContext.getTypeEvalContext()); - return clarifiedResolved == null ? null : new ClarifiedResolveResult(resolveResult, clarifiedResolved, null, true); + return ContainerUtil.map(((PyClass)resolved).multiFindInitOrNew(true, resolveContext.getTypeEvalContext()), + function -> new ClarifiedResolveResult(resolveResult, function, null, true)); } else if (resolved instanceof PyCallExpression) { // foo = classmethod(foo) final Pair wrapperInfo = interpretAsModifierWrappingCall((PyCallExpression)resolved); @@ -206,7 +205,8 @@ public class PyCallExpressionHelper { ? PyFunction.Modifier.STATICMETHOD : null; - return new ClarifiedResolveResult(resolveResult, wrapperInfo.getSecond(), wrappedModifier, false); + final ClarifiedResolveResult result = new ClarifiedResolveResult(resolveResult, wrapperInfo.getSecond(), wrappedModifier, false); + return Collections.singletonList(result); } } else if (resolved instanceof PyFunction) { @@ -217,12 +217,14 @@ public class PyCallExpressionHelper { final PyType type = context.getReturnType(function); return type instanceof PyFunctionType - ? new ClarifiedResolveResult(resolveResult, ((PyFunctionType)type).getCallable(), null, false) - : null; + ? Collections.singletonList(new ClarifiedResolveResult(resolveResult, ((PyFunctionType)type).getCallable(), null, false)) + : Collections.emptyList(); } } - return resolved == null ? null : new ClarifiedResolveResult(resolveResult, resolved, null, false); + return resolved != null + ? Collections.singletonList(new ClarifiedResolveResult(resolveResult, resolved, null, false)) + : Collections.emptyList(); } @Nullable diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 448a53da9856..b8115fdd5782 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -422,7 +422,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla @Override public ItemPresentation getPresentation() { return new PyElementPresentation(this) { - @Nullable + @NotNull @Override public String getPresentableText() { PyPsiUtils.assertValid(PyClassImpl.this); @@ -709,6 +709,17 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla return proc.getResult(); } + @NotNull + @Override + public List multiFindInitOrNew(boolean inherited, @Nullable TypeEvalContext context) { + final MultiNameFinder processor = isNewStyleClass(context) + ? new MultiNameFinder<>(PyNames.INIT, PyNames.NEW) + : new MultiNameFinder<>(PyNames.INIT); + + visitMethods(processor, inherited, true, context); + return processor.myResult; + } + private final static Maybe UNKNOWN_CALL = new Maybe<>(); // denotes _not_ a PyFunction, actually private final static Maybe NONE = new Maybe<>(null); // denotes an explicit None diff --git a/python/testData/inspections/PyArgumentListInspection/builtinLong.py b/python/testData/inspections/PyArgumentListInspection/builtinLong.py new file mode 100644 index 000000000000..d79009ff16a1 --- /dev/null +++ b/python/testData/inspections/PyArgumentListInspection/builtinLong.py @@ -0,0 +1 @@ +long("abc") \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyArgumentListInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyArgumentListInspectionTest.java index fa786b2cb2c9..cf00761d87dc 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyArgumentListInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyArgumentListInspectionTest.java @@ -312,6 +312,11 @@ public class PyArgumentListInspectionTest extends PyTestCase { runWithLanguageLevel(LanguageLevel.PYTHON35, this::doTest); } + // PY-24286 + public void testBuiltinLong() { + doTest(); + } + private void doMultiFileTest() { final String folderPath = "inspections/PyArgumentListInspection/" + getTestName(false) + "/";