PY-34478 Properly follow assignment chains for type aliases

We used to implicitly rely on PyTypingTypeProvider.getClassType() for this purpose
that, in turn, uses normal resolve machinery of a PyReference. But it (rightfully)
didn't work for references inside fragments created from text of alias RHS parts
as we prohibit resolving in them to avoid unstubbing of their containing files.
This commit is contained in:
Mikhail Golubev
2019-03-11 16:56:24 +00:00
parent 75ae8dfe44
commit 18c6ef8120
5 changed files with 45 additions and 0 deletions
@@ -828,6 +828,15 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
if (anyType != null) {
return anyType;
}
// We perform chained resolve only for actual aliases as tryResolvingWithAliases() returns the passed-in
// expression both when it's not a reference expression and when it's failed to resolve it, hence we might
// hit SOE for mere unresolved references in the latter case.
if (alias != null) {
final Ref<PyType> aliasedType = getAliasedType(resolved, context);
if (aliasedType != null) {
return aliasedType;
}
}
final Ref<PyType> classType = getClassType(resolved, context.getTypeContext());
if (classType != null) {
return classType;
@@ -841,6 +850,14 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
}
}
@Nullable
private static Ref<PyType> getAliasedType(@NotNull PsiElement resolved, @NotNull Context context) {
if (resolved instanceof PyReferenceExpression && ((PyReferenceExpression)resolved).asQualifiedName() != null) {
return getType((PyExpression)resolved, context);
}
return null;
}
@Nullable
private static PyType addTypeVarAlias(@Nullable PyType type, @Nullable PyTargetExpression alias) {
final PyGenericType typeVar = as(type, PyGenericType.class);
@@ -0,0 +1,2 @@
alias2 = 'alias'
alias = alias2
@@ -0,0 +1 @@
alias = str
@@ -0,0 +1 @@
alias = unresolved
@@ -1424,6 +1424,30 @@ public class PyTypingTest extends PyTestCase {
"\n");
}
// PY-34478
public void testTrivialTypeAliasInAnotherFile() {
doMultiFileStubAwareTest("str",
"from other import alias\n" +
"\n" +
"expr: alias");
}
// PY-34478
public void testTrivialUnresolvedTypeAliasInAnotherFile() {
doMultiFileStubAwareTest("Any",
"from other import alias\n" +
"\n" +
"expr: alias");
}
// PY-34478
public void testTrivialRecursiveTypeAliasInAnotherFile() {
doMultiFileStubAwareTest("Any",
"from other import alias\n" +
"\n" +
"expr: alias");
}
private void doTestNoInjectedText(@NotNull String text) {
myFixture.configureByText(PythonFileType.INSTANCE, text);
final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject());