mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-22801 Fixed: False positive for long(number) in Python 2
Callee could be resolved to a class and we have to take all overloads while replacing resolved class with its `__init__` or `__new__` method. As a result PyClass.multiFindInitOrNew is introduced and is used inside PyCallExpressionHelper.clarifyResolveResult.
This commit is contained in:
committed by
Semyon Proshev
parent
59a909ff25
commit
302caea766
@@ -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<PyFunction> 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<String> getOwnSlots();
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
String getDocStringValue();
|
||||
|
||||
|
||||
@@ -130,13 +130,12 @@ public class PyCallExpressionHelper {
|
||||
final List<PyCallExpression.PyRatedMarkedCallee> 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<ClarifiedResolveResult> 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<String, PyFunction> 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
|
||||
|
||||
@@ -422,7 +422,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> 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<PyClassStub> implements PyCla
|
||||
return proc.getResult();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<PyFunction> multiFindInitOrNew(boolean inherited, @Nullable TypeEvalContext context) {
|
||||
final MultiNameFinder<PyFunction> 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<PyCallable> UNKNOWN_CALL = new Maybe<>(); // denotes _not_ a PyFunction, actually
|
||||
private final static Maybe<PyCallable> NONE = new Maybe<>(null); // denotes an explicit None
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
long("abc")
|
||||
@@ -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) + "/";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user