mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-61878 Resolve type parameters and type aliases on stubs
Do not resolve type parameters as class members Tests for the changes above Co-authored-by: Mikhail Golubev <mikhail.golubev@jetbrains.com> GitOrigin-RevId: 96309ebedf26d04e375bfa3a5f8ae0bc9257d48f
This commit is contained in:
committed by
intellij-monorepo-bot
co-authored by
Mikhail Golubev
parent
eb58a3805e
commit
b83be81bb7
@@ -1860,6 +1860,11 @@ public abstract class PyCommonResolveTest extends PyCommonResolveTestCase {
|
||||
assertResolvesTo(PyClass.class, "Nested");
|
||||
}
|
||||
|
||||
// PY-61877
|
||||
public void testNewStyleTypeParameterNotResolvedAsClassAttribute() {
|
||||
assertNotResolved();
|
||||
}
|
||||
|
||||
// [TODO] daniil.kalinin enable when resolve for collisions in type parameter names and class attribute names is implemented
|
||||
// PY-61877
|
||||
//public void testClassAttributeDeclarationWithSameAsTypeParameterNameNotResolvedToTypeParameter() {
|
||||
|
||||
@@ -267,20 +267,20 @@ public final class PyResolveUtil {
|
||||
final PyResolveContext resolveContext = PyResolveContext.defaultContext(context);
|
||||
|
||||
final List<? extends RatedResolveResult> unqualifiedResults;
|
||||
if (scopeOwner instanceof PyiFile) {
|
||||
if (scopeOwner instanceof PyiFile fileScope) {
|
||||
// pyi-stubs are special cased because
|
||||
// `resolveMember` delegates to `multiResolveName(..., true)` and
|
||||
// it skips elements that are imported without `as`
|
||||
unqualifiedResults = ((PyiFile)scopeOwner).multiResolveName(firstName, false);
|
||||
unqualifiedResults = fileScope.multiResolveName(firstName, false);
|
||||
}
|
||||
else if (scopeOwner instanceof PyFunction) {
|
||||
else if (scopeOwner instanceof PyFunction functionScope) {
|
||||
final Stream<PsiNamedElement> targets = StreamEx
|
||||
.of(PsiTreeUtil.getStubChildrenOfTypeAsList(scopeOwner, PyTargetExpression.class))
|
||||
.filter(it -> !it.isQualified())
|
||||
.select(PsiNamedElement.class);
|
||||
|
||||
final Stream<PsiNamedElement> parameters = StreamEx
|
||||
.of(((PyFunction)scopeOwner).getParameterList().getParameters())
|
||||
.of(functionScope.getParameterList().getParameters())
|
||||
.select(PsiNamedElement.class);
|
||||
|
||||
unqualifiedResults = StreamEx
|
||||
@@ -288,13 +288,22 @@ public final class PyResolveUtil {
|
||||
.append(parameters)
|
||||
.filter(it -> firstName.equals(it.getName()))
|
||||
.map(it -> new RatedResolveResult(RatedResolveResult.RATE_NORMAL, it))
|
||||
.append(resolveTypeParameters(functionScope, firstName))
|
||||
.toList();
|
||||
}
|
||||
else if (scopeOwner instanceof PyTypeAliasStatement) {
|
||||
unqualifiedResults = resolveTypeParameters((PyTypeParameterListOwner)scopeOwner, firstName);
|
||||
}
|
||||
else {
|
||||
final PyType scopeType = context.getType((PyTypedElement)scopeOwner);
|
||||
if (scopeType == null) return Collections.emptyList();
|
||||
|
||||
unqualifiedResults = scopeType.resolveMember(firstName, null, AccessDirection.READ, resolveContext);
|
||||
List<? extends RatedResolveResult> typeMembers = scopeType.resolveMember(firstName, null, AccessDirection.READ, resolveContext);
|
||||
if (scopeOwner instanceof PyClass pyClass) {
|
||||
unqualifiedResults = ContainerUtil.concat(ContainerUtil.notNullize(typeMembers), resolveTypeParameters(pyClass, firstName));
|
||||
}
|
||||
else {
|
||||
unqualifiedResults = typeMembers;
|
||||
}
|
||||
}
|
||||
|
||||
final StreamEx<RatedResolveResult> initialResults;
|
||||
@@ -520,4 +529,18 @@ public final class PyResolveUtil {
|
||||
|
||||
return reference.resolve();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<RatedResolveResult> resolveTypeParameters(@NotNull PyTypeParameterListOwner typeParameterListOwner,
|
||||
@NotNull String name) {
|
||||
if (typeParameterListOwner.getTypeParameterList() != null) {
|
||||
return StreamEx.of(typeParameterListOwner.getTypeParameterList().getTypeParameters())
|
||||
.filter(it -> name.equals(it.getName()))
|
||||
.map(it -> new RatedResolveResult(RatedResolveResult.RATE_NORMAL, it))
|
||||
.toList();
|
||||
}
|
||||
else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -777,6 +777,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
@Override
|
||||
protected boolean tryAddResult(@Nullable PsiElement element, @Nullable PyImportedNameDefiner definer) {
|
||||
PsiElement psiElement = definer != null ? definer : element;
|
||||
if (element instanceof PyTypeParameter) return false;
|
||||
if (inSameScope(psiElement, myLocation)) {
|
||||
if (PsiTreeUtil.isAncestor(psiElement, myLocation, false) ||
|
||||
PyDefUseUtil.isDefinedBefore(psiElement, myLocation) ||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class C[T]:
|
||||
pass
|
||||
|
||||
print(C.T)
|
||||
<ref>
|
||||
Reference in New Issue
Block a user