mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 03:21:12 +07:00
PY-22971 Fixed: Support @typing.overload in regular Python files, not only in Python stubs
Resolve: * resolve to the first implementation in class, if there is no implementation, resolve to the first overload * resolve to the last implementation in module, if there is no implementation, resolve to the last overload
This commit is contained in:
committed by
Semyon Proshev
parent
986cfc4921
commit
947930f6c9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,6 +54,8 @@ import com.jetbrains.python.psi.stubs.PyFileStub;
|
||||
import com.jetbrains.python.psi.types.PyModuleType;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import com.jetbrains.python.pyi.PyiTypeProvider;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -180,7 +182,8 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression {
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultList;
|
||||
|
||||
return containsOverloads(resultList, typeEvalContext) ? moveOverloadsBack(resultList, typeEvalContext) : resultList;
|
||||
}
|
||||
|
||||
synchronized (myNameDefinerNegativeCache) {
|
||||
@@ -192,6 +195,34 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression {
|
||||
public long getModificationStamp() {
|
||||
return myModificationStamp;
|
||||
}
|
||||
|
||||
private boolean containsOverloads(@NotNull List<RatedResolveResult> resolveResults, @NotNull TypeEvalContext context) {
|
||||
return StreamEx
|
||||
.of(resolveResults)
|
||||
.map(RatedResolveResult::getElement)
|
||||
.anyMatch(element -> element instanceof PyCallable && PyiTypeProvider.isOverload((PyCallable)element, context));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<RatedResolveResult> moveOverloadsBack(@NotNull List<RatedResolveResult> resolveResults, @NotNull TypeEvalContext context) {
|
||||
return StreamEx
|
||||
.of(resolveResults)
|
||||
.sorted(
|
||||
(r1, r2) -> {
|
||||
final PsiElement e1 = r1.getElement();
|
||||
final PsiElement e2 = r2.getElement();
|
||||
if (e1 instanceof PyCallable && e2 instanceof PyCallable) {
|
||||
final boolean firstIsOverload = PyiTypeProvider.isOverload((PyCallable)e1, context);
|
||||
final boolean secondIsOverload = PyiTypeProvider.isOverload((PyCallable)e2, context);
|
||||
|
||||
return Boolean.compare(firstIsOverload, secondIsOverload);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
public PyFileImpl(FileViewProvider viewProvider) {
|
||||
@@ -210,6 +241,7 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression {
|
||||
return PythonFileType.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PyFile:" + getName();
|
||||
}
|
||||
@@ -444,6 +476,7 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression {
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PsiElement getElementNamed(final String name) {
|
||||
final List<RatedResolveResult> results = multiResolveName(name);
|
||||
@@ -458,6 +491,7 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Iterable<PyElement> iterateNames() {
|
||||
final List<PyElement> result = new ArrayList<>();
|
||||
|
||||
@@ -278,7 +278,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
|
||||
.select(PyCallable.class)
|
||||
.filter(callable -> PyiTypeProvider.isOverload(callable, typeEvalContext))
|
||||
.map(callable -> new RatedResolveResult(getRate(callable, typeEvalContext), callable))
|
||||
.append(latestDefs)
|
||||
.prepend(latestDefs)
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
||||
@@ -44,12 +44,15 @@ import com.jetbrains.python.psi.resolve.CompletionVariantsProcessor;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveProcessor;
|
||||
import com.jetbrains.python.psi.resolve.RatedResolveResult;
|
||||
import com.jetbrains.python.pyi.PyiTypeProvider;
|
||||
import com.jetbrains.python.toolbox.Maybe;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.jetbrains.python.psi.PyUtil.as;
|
||||
import static com.jetbrains.python.psi.resolve.PyResolveImportUtil.fromFoothold;
|
||||
@@ -118,7 +121,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
public PyClassLikeType toClass() {
|
||||
return myIsDefinition ? this : new PyClassTypeImpl(myClass, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wrap new instance to copy user data to it
|
||||
*/
|
||||
@@ -208,7 +211,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
}
|
||||
}
|
||||
|
||||
final List<? extends RatedResolveResult> classMembers = resolveInner(myClass, myIsDefinition, name, location);
|
||||
final List<? extends RatedResolveResult> classMembers = resolveInner(myClass, myIsDefinition, name, location, context);
|
||||
|
||||
if (PyNames.__CLASS__.equals(name)) {
|
||||
return resolveDunderClass(context, classMembers);
|
||||
@@ -244,7 +247,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
type = type.toInstance();
|
||||
}
|
||||
final List<? extends RatedResolveResult> superMembers =
|
||||
resolveInner(((PyClassType)type).getPyClass(), myIsDefinition, name, location);
|
||||
resolveInner(((PyClassType)type).getPyClass(), myIsDefinition, name, location, context);
|
||||
if (!superMembers.isEmpty()) {
|
||||
return superMembers;
|
||||
}
|
||||
@@ -549,24 +552,53 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
private static List<? extends RatedResolveResult> resolveInner(@NotNull PyClass cls,
|
||||
boolean isDefinition,
|
||||
@NotNull String name,
|
||||
@Nullable PyExpression location) {
|
||||
@Nullable PyExpression location,
|
||||
@NotNull TypeEvalContext context) {
|
||||
final PyResolveProcessor processor = new PyResolveProcessor(name);
|
||||
final Collection<PsiElement> result;
|
||||
final Stream<PsiElement> result;
|
||||
|
||||
if (!isDefinition && !cls.processInstanceLevelDeclarations(processor, location)) {
|
||||
result = processor.getElements();
|
||||
result = processor.getElements().stream();
|
||||
}
|
||||
else {
|
||||
cls.processClassLevelDeclarations(processor);
|
||||
result = processor.getElements();
|
||||
final Collection<PsiElement> elements = processor.getElements();
|
||||
result = containsOverloads(elements, context) ? moveOverloadsBack(elements, context) : elements.stream();
|
||||
}
|
||||
|
||||
return ContainerUtil.map(result, element -> new RatedResolveResult(RatedResolveResult.RATE_NORMAL, element));
|
||||
return StreamEx
|
||||
.of(result)
|
||||
.map(element -> new RatedResolveResult(RatedResolveResult.RATE_NORMAL, element))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static boolean containsOverloads(@NotNull Collection<PsiElement> elements, @NotNull TypeEvalContext context) {
|
||||
return ContainerUtil.exists(elements,
|
||||
element -> element instanceof PyCallable && PyiTypeProvider.isOverload((PyCallable)element, context));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Stream<PsiElement> moveOverloadsBack(@NotNull Collection<PsiElement> elements, @NotNull TypeEvalContext context) {
|
||||
return elements
|
||||
.stream()
|
||||
.sorted(
|
||||
(e1, e2) -> {
|
||||
if (e1 instanceof PyCallable && e2 instanceof PyCallable) {
|
||||
final boolean firstIsOverload = PyiTypeProvider.isOverload((PyCallable)e1, context);
|
||||
final boolean secondIsOverload = PyiTypeProvider.isOverload((PyCallable)e2, context);
|
||||
|
||||
return Boolean.compare(firstIsOverload, secondIsOverload);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private static Key<Set<PyClassType>> CTX_VISITED = Key.create("PyClassType.Visited");
|
||||
public static Key<Boolean> CTX_SUPPRESS_PARENTHESES = Key.create("PyFunction.SuppressParentheses");
|
||||
|
||||
@Override
|
||||
public Object[] getCompletionVariants(String prefix, PsiElement location, ProcessingContext context) {
|
||||
Set<PyClassType> visited = context.get(CTX_VISITED);
|
||||
if (visited == null) {
|
||||
@@ -794,6 +826,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
return lookupString.startsWith("_") && !lookupString.startsWith("__");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getName() {
|
||||
return getPyClass().getName();
|
||||
}
|
||||
@@ -842,6 +876,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
return (isValid() ? "" : "[INVALID] ") + "PyClassType: " + getClassQName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return myClass.isValid();
|
||||
}
|
||||
@@ -881,6 +916,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean value(final PsiElement target) {
|
||||
return (instance != target);
|
||||
}
|
||||
|
||||
22
python/testData/resolve/OverloadsAndImplementationInClass.py
Normal file
22
python/testData/resolve/OverloadsAndImplementationInClass.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from typing import overload
|
||||
|
||||
|
||||
class A:
|
||||
@overload
|
||||
def foo(self, value: None) -> None:
|
||||
pass
|
||||
|
||||
@overload
|
||||
def foo(self, value: int) -> str:
|
||||
pass
|
||||
|
||||
@overload
|
||||
def foo(self, value: str) -> str:
|
||||
pass
|
||||
|
||||
def foo(self, value):
|
||||
return None
|
||||
|
||||
|
||||
A().foo("abc")
|
||||
<ref>
|
||||
@@ -0,0 +1,5 @@
|
||||
from OverloadsAndImplementationInImportedClassDep import A
|
||||
|
||||
|
||||
A().foo("abc")
|
||||
<ref>
|
||||
@@ -0,0 +1,18 @@
|
||||
from typing import overload
|
||||
|
||||
|
||||
class A:
|
||||
@overload
|
||||
def foo(self, value: None) -> None:
|
||||
pass
|
||||
|
||||
@overload
|
||||
def foo(self, value: int) -> str:
|
||||
pass
|
||||
|
||||
@overload
|
||||
def foo(self, value: str) -> str:
|
||||
pass
|
||||
|
||||
def foo(self, value):
|
||||
return None
|
||||
@@ -0,0 +1,5 @@
|
||||
from OverloadsAndImplementationInImportedModuleDep import foo
|
||||
|
||||
|
||||
foo("abc")
|
||||
<ref>
|
||||
@@ -0,0 +1,20 @@
|
||||
from typing import overload
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: None) -> None:
|
||||
pass
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: int) -> str:
|
||||
pass
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: str) -> str:
|
||||
pass
|
||||
|
||||
|
||||
def foo(value):
|
||||
return None
|
||||
@@ -0,0 +1,25 @@
|
||||
from typing import overload
|
||||
|
||||
|
||||
class A:
|
||||
@overload
|
||||
def foo(self, value: None) -> None:
|
||||
pass
|
||||
|
||||
def foo(self, value):
|
||||
return None
|
||||
|
||||
@overload
|
||||
def foo(self, value: int) -> str:
|
||||
pass
|
||||
|
||||
def foo(self, value):
|
||||
return None
|
||||
|
||||
@overload
|
||||
def foo(self, value: str) -> str:
|
||||
pass
|
||||
|
||||
|
||||
A().foo("abc")
|
||||
<ref>
|
||||
@@ -0,0 +1,5 @@
|
||||
from OverloadsAndImplementationsInImportedClassDep import A
|
||||
|
||||
|
||||
A().foo("abc")
|
||||
<ref>
|
||||
@@ -0,0 +1,21 @@
|
||||
from typing import overload
|
||||
|
||||
|
||||
class A:
|
||||
@overload
|
||||
def foo(self, value: None) -> None:
|
||||
pass
|
||||
|
||||
def foo(self, value):
|
||||
return None
|
||||
|
||||
@overload
|
||||
def foo(self, value: int) -> str:
|
||||
pass
|
||||
|
||||
def foo(self, value):
|
||||
return None
|
||||
|
||||
@overload
|
||||
def foo(self, value: str) -> str:
|
||||
pass
|
||||
@@ -0,0 +1,5 @@
|
||||
from OverloadsAndImplementationsInImportedModuleDep import foo
|
||||
|
||||
|
||||
foo("abc")
|
||||
<ref>
|
||||
@@ -0,0 +1,24 @@
|
||||
from typing import overload
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: None) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def foo(value):
|
||||
return None
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: int) -> str:
|
||||
pass
|
||||
|
||||
|
||||
def foo(value):
|
||||
return None
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: str) -> str:
|
||||
pass
|
||||
@@ -0,0 +1,19 @@
|
||||
from typing import overload
|
||||
|
||||
|
||||
class A:
|
||||
@overload
|
||||
def foo(self, value: None) -> None:
|
||||
pass
|
||||
|
||||
@overload
|
||||
def foo(self, value: int) -> str:
|
||||
pass
|
||||
|
||||
@overload
|
||||
def foo(self, value: str) -> str:
|
||||
pass
|
||||
|
||||
|
||||
A().foo("abc")
|
||||
<ref>
|
||||
@@ -0,0 +1,5 @@
|
||||
from OverloadsAndNoImplementationInImportedClassDep import A
|
||||
|
||||
|
||||
A().foo("abc")
|
||||
<ref>
|
||||
@@ -0,0 +1,15 @@
|
||||
from typing import overload
|
||||
|
||||
|
||||
class A:
|
||||
@overload
|
||||
def foo(self, value: None) -> None:
|
||||
pass
|
||||
|
||||
@overload
|
||||
def foo(self, value: int) -> str:
|
||||
pass
|
||||
|
||||
@overload
|
||||
def foo(self, value: str) -> str:
|
||||
pass
|
||||
@@ -0,0 +1,5 @@
|
||||
from OverloadsAndNoImplementationInImportedModuleDep import foo
|
||||
|
||||
|
||||
foo("abc")
|
||||
<ref>
|
||||
@@ -0,0 +1,16 @@
|
||||
from typing import overload
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: None) -> None:
|
||||
pass
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: int) -> str:
|
||||
pass
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: str) -> str:
|
||||
pass
|
||||
@@ -0,0 +1,24 @@
|
||||
from typing import overload
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: None) -> None:
|
||||
pass
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: int) -> str:
|
||||
pass
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: str) -> str:
|
||||
pass
|
||||
|
||||
|
||||
def foo(value):
|
||||
return None
|
||||
|
||||
|
||||
foo("abc")
|
||||
<ref>
|
||||
@@ -0,0 +1,28 @@
|
||||
from typing import overload
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: None) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def foo(value):
|
||||
return None
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: int) -> str:
|
||||
pass
|
||||
|
||||
|
||||
def foo(value):
|
||||
return None
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: str) -> str:
|
||||
pass
|
||||
|
||||
|
||||
foo("abc")
|
||||
<ref>
|
||||
@@ -0,0 +1,20 @@
|
||||
from typing import overload
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: None) -> None:
|
||||
pass
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: int) -> str:
|
||||
pass
|
||||
|
||||
|
||||
@overload
|
||||
def foo(value: str) -> str:
|
||||
pass
|
||||
|
||||
|
||||
foo("abc")
|
||||
<ref>
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,10 @@ import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.jetbrains.python.fixtures.PyResolveTestCase;
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyPsiUtils;
|
||||
import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import com.jetbrains.python.pyi.PyiTypeProvider;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
@@ -364,4 +367,230 @@ public class Py3ResolveTest extends PyResolveTestCase {
|
||||
public void testLocalVariableAnnotationWithInnerClass() {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON36, () -> assertResolvesTo(PyClass.class, "MyType"));
|
||||
}
|
||||
|
||||
// PY-22971
|
||||
public void testOverloadsAndNoImplementationInClass() {
|
||||
// resolve to the first overload
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON35,
|
||||
() -> {
|
||||
final PyFunction foo = assertResolvesTo(PyFunction.class, "foo");
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), myFixture.getFile());
|
||||
|
||||
PyiTypeProvider
|
||||
.getOverloads(foo, context)
|
||||
.forEach(
|
||||
overload -> {
|
||||
if (overload != foo) assertTrue(PyPsiUtils.isBefore(foo, overload));
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// PY-22971
|
||||
public void testOverloadsAndImplementationInClass() {
|
||||
// resolve to the implementation
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON35,
|
||||
() -> {
|
||||
final PyFunction foo = assertResolvesTo(PyFunction.class, "foo");
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), myFixture.getFile());
|
||||
assertFalse(PyiTypeProvider.isOverload(foo, context));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// PY-22971
|
||||
public void testOverloadsAndImplementationsInClass() {
|
||||
// resolve to the first implementation
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON35,
|
||||
() -> {
|
||||
final PyFunction foo = assertResolvesTo(PyFunction.class, "foo");
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), myFixture.getFile());
|
||||
assertFalse(PyiTypeProvider.isOverload(foo, context));
|
||||
|
||||
final PyClass pyClass = foo.getContainingClass();
|
||||
assertNotNull(pyClass);
|
||||
|
||||
pyClass.visitMethods(
|
||||
function -> {
|
||||
assertTrue(PyiTypeProvider.isOverload(function, context) || function == foo || PyPsiUtils.isBefore(foo, function));
|
||||
return true;
|
||||
},
|
||||
false,
|
||||
context
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// PY-22971
|
||||
public void testTopLevelOverloadsAndNoImplementation() {
|
||||
// resolve to the last overload
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON35,
|
||||
() -> {
|
||||
final PyFunction foo = assertResolvesTo(PyFunction.class, "foo");
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), myFixture.getFile());
|
||||
|
||||
PyiTypeProvider
|
||||
.getOverloads(foo, context)
|
||||
.forEach(
|
||||
overload -> {
|
||||
if (overload != foo) assertTrue(PyPsiUtils.isBefore(overload, foo));
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// PY-22971
|
||||
public void testTopLevelOverloadsAndImplementation() {
|
||||
// resolve to the implementation
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON35,
|
||||
() -> {
|
||||
final PyFunction foo = assertResolvesTo(PyFunction.class, "foo");
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), myFixture.getFile());
|
||||
assertFalse(PyiTypeProvider.isOverload(foo, context));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// PY-22971
|
||||
public void testTopLevelOverloadsAndImplementations() {
|
||||
// resolve to the last overload
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON35,
|
||||
() -> {
|
||||
final PyFunction foo = assertResolvesTo(PyFunction.class, "foo");
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), myFixture.getFile());
|
||||
assertTrue(PyiTypeProvider.isOverload(foo, context));
|
||||
|
||||
((PyFile)foo.getContainingFile())
|
||||
.getTopLevelFunctions()
|
||||
.forEach(
|
||||
function -> assertTrue(function == foo || PyPsiUtils.isBefore(function, foo))
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// PY-22971
|
||||
public void testOverloadsAndNoImplementationInImportedClass() {
|
||||
// resolve to the first overload
|
||||
myFixture.copyDirectoryToProject("resolve/OverloadsAndNoImplementationInImportedClassDep", "OverloadsAndNoImplementationInImportedClassDep");
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON35,
|
||||
() -> {
|
||||
final PyFunction foo = assertResolvesTo(PyFunction.class, "foo");
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), myFixture.getFile());
|
||||
|
||||
PyiTypeProvider
|
||||
.getOverloads(foo, context)
|
||||
.forEach(
|
||||
overload -> {
|
||||
if (overload != foo) assertTrue(PyPsiUtils.isBefore(foo, overload));
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// PY-22971
|
||||
public void testOverloadsAndImplementationInImportedClass() {
|
||||
// resolve to the implementation
|
||||
myFixture.copyDirectoryToProject("resolve/OverloadsAndImplementationInImportedClassDep", "OverloadsAndImplementationInImportedClassDep");
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON35,
|
||||
() -> {
|
||||
final PyFunction foo = assertResolvesTo(PyFunction.class, "foo");
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), myFixture.getFile());
|
||||
assertFalse(PyiTypeProvider.isOverload(foo, context));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// PY-22971
|
||||
public void testOverloadsAndImplementationsInImportedClass() {
|
||||
// resolve to the first implementation
|
||||
myFixture.copyDirectoryToProject("resolve/OverloadsAndImplementationsInImportedClassDep", "OverloadsAndImplementationsInImportedClassDep");
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON35,
|
||||
() -> {
|
||||
final PyFunction foo = assertResolvesTo(PyFunction.class, "foo");
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), myFixture.getFile());
|
||||
assertFalse(PyiTypeProvider.isOverload(foo, context));
|
||||
|
||||
final PyClass pyClass = foo.getContainingClass();
|
||||
assertNotNull(pyClass);
|
||||
|
||||
pyClass.visitMethods(
|
||||
function -> {
|
||||
assertTrue(PyiTypeProvider.isOverload(function, context) || function == foo || PyPsiUtils.isBefore(foo, function));
|
||||
return true;
|
||||
},
|
||||
false,
|
||||
context
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// PY-22971
|
||||
public void testOverloadsAndNoImplementationInImportedModule() {
|
||||
// resolve to the last overload
|
||||
myFixture.copyDirectoryToProject("resolve/OverloadsAndNoImplementationInImportedModuleDep", "OverloadsAndNoImplementationInImportedModuleDep");
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON35,
|
||||
() -> {
|
||||
final PyFunction foo = assertResolvesTo(PyFunction.class, "foo");
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), myFixture.getFile());
|
||||
|
||||
PyiTypeProvider
|
||||
.getOverloads(foo, context)
|
||||
.forEach(
|
||||
overload -> {
|
||||
if (overload != foo) assertTrue(PyPsiUtils.isBefore(overload, foo));
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// PY-22971
|
||||
public void testOverloadsAndImplementationInImportedModule() {
|
||||
// resolve to the implementation
|
||||
myFixture.copyDirectoryToProject("resolve/OverloadsAndImplementationInImportedModuleDep", "OverloadsAndImplementationInImportedModuleDep");
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON35,
|
||||
() -> {
|
||||
final PyFunction foo = assertResolvesTo(PyFunction.class, "foo");
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), myFixture.getFile());
|
||||
assertFalse(PyiTypeProvider.isOverload(foo, context));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// PY-22971
|
||||
public void testOverloadsAndImplementationsInImportedModule() {
|
||||
// resolve to the last implementation
|
||||
myFixture.copyDirectoryToProject("resolve/OverloadsAndImplementationsInImportedModuleDep", "OverloadsAndImplementationsInImportedModuleDep");
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON35,
|
||||
() -> {
|
||||
final PyFunction foo = assertResolvesTo(PyFunction.class, "foo");
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), myFixture.getFile());
|
||||
assertFalse(PyiTypeProvider.isOverload(foo, context));
|
||||
|
||||
((PyFile)foo.getContainingFile())
|
||||
.getTopLevelFunctions()
|
||||
.forEach(
|
||||
function -> assertTrue(PyiTypeProvider.isOverload(function, context) || function == foo || PyPsiUtils.isBefore(function, foo))
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user