PY-39682 Handle union types of qualifiers when deducing FQN for unresolved attributes

The underlying problem is that we started to infer a confusing union type
of __init__.py modules found both in site-packages and python_stubs
for such imported packages, but I want it to be addressed separately in PY-39911.

GitOrigin-RevId: 053a4a092ce7fcc71d192dbaa6b1623b82472a17
This commit is contained in:
Mikhail Golubev
2019-12-25 21:18:20 +03:00
committed by intellij-monorepo-bot
parent d5073a50b2
commit c955ffbcc7
6 changed files with 57 additions and 35 deletions

View File

@@ -661,44 +661,43 @@ abstract class PyUnresolvedReferencesVisitor extends PyInspectionVisitor {
final String exprName = expr.getName();
if (exprName != null) {
if (qualifier != null) {
final PyType type = context.getType(qualifier);
if (type instanceof PyClassType) {
ContainerUtil.addIfNotNull(result, extractAttributeQNameFromClassType(exprName, (PyClassType)type));
}
else if (type instanceof PyModuleType) {
final PyFile file = ((PyModuleType)type).getModule();
final QualifiedName name = QualifiedNameFinder.findCanonicalImportPath(file, element);
if (name != null) {
ContainerUtil.addIfNotNull(result, name.append(exprName));
}
}
else if (type instanceof PyImportedModuleType) {
final PyImportedModule module = ((PyImportedModuleType)type).getImportedModule();
final PsiElement resolved = module.resolve();
if (resolved != null) {
final QualifiedName path = QualifiedNameFinder.findCanonicalImportPath(resolved, element);
if (path != null) {
ContainerUtil.addIfNotNull(result, path.append(exprName));
final PyType qualifierType = context.getType(qualifier);
PyTypeUtil.toStream(qualifierType)
.map(type -> {
if (type instanceof PyClassType) {
return extractAttributeQNameFromClassType(exprName, (PyClassType)type);
}
}
}
else if (type instanceof PyFunctionType) {
final PyCallable callable = ((PyFunctionType)type).getCallable();
final String callableName = callable.getName();
if (callableName != null) {
final QualifiedName path = QualifiedNameFinder.findCanonicalImportPath(callable, element);
if (path != null) {
result.add(path.append(QualifiedName.fromComponents(callableName, exprName)));
else if (type instanceof PyModuleType) {
final PyFile file = ((PyModuleType)type).getModule();
final QualifiedName name = QualifiedNameFinder.findCanonicalImportPath(file, element);
if (name != null) {
return name.append(exprName);
}
}
}
}
else if (type instanceof PyUnionType) {
for (PyType memberType : ((PyUnionType)type).getMembers()) {
if (memberType instanceof PyClassType) {
ContainerUtil.addIfNotNull(result, extractAttributeQNameFromClassType(exprName, (PyClassType)memberType));
else if (type instanceof PyImportedModuleType) {
final PyImportedModule module = ((PyImportedModuleType)type).getImportedModule();
final PsiElement resolved = module.resolve();
if (resolved != null) {
final QualifiedName path = QualifiedNameFinder.findCanonicalImportPath(resolved, element);
if (path != null) {
return path.append(exprName);
}
}
}
}
}
else if (type instanceof PyFunctionType) {
final PyCallable callable = ((PyFunctionType)type).getCallable();
final String callableName = callable.getName();
if (callableName != null) {
final QualifiedName path = QualifiedNameFinder.findCanonicalImportPath(callable, element);
if (path != null) {
return path.append(QualifiedName.fromComponents(callableName, exprName));
}
}
}
return null;
})
.nonNull()
.into(result);
}
else {
final PsiElement parent = element.getParent();

View File

@@ -828,6 +828,25 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase {
"a.<warning descr=\"Cannot find reference 'append' in 'None'\">append</warning>(10)");
}
// PY-39682
public void testWildcardIgnorePatternReferenceForNestedBinaryModule() {
// TODO simplify runWithAdditionalClassEntryInSdkRoots to accept a relative path directly
final String testDataDir = getTestDataPath() + "/" + getTestDirectoryPath();
final VirtualFile sitePackagesDir = StandardFileSystems.local().findFileByPath(testDataDir + "/site-packages");
final VirtualFile skeletonsDir = StandardFileSystems.local().findFileByPath(testDataDir + "/python_stubs");
runWithAdditionalClassEntryInSdkRoots(sitePackagesDir, () -> {
runWithAdditionalClassEntryInSdkRoots(skeletonsDir, () -> {
myFixture.configureByFile(getTestDirectoryPath() + "/a.py");
final PyUnresolvedReferencesInspection inspection = new PyUnresolvedReferencesInspection();
inspection.ignoredIdentifiers.add("pkg.*");
myFixture.enableInspections(inspection);
myFixture.checkHighlighting(isWarning(), isInfo(), isWeakWarning());
assertSdkRootsNotParsed(myFixture.getFile());
assertProjectFilesNotParsed(myFixture.getFile());
});
});
}
@NotNull
@Override
protected Class<? extends PyInspection> getInspectionClass() {