mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-47281 Re-use QualifiedNameBasedScope in PyQualifiedNameCompletionMatcher
GitOrigin-RevId: f8407f86e083bc36f1be80b6fa43348a350511f2
This commit is contained in:
committed by
intellij-monorepo-bot
parent
363e6c68ec
commit
df979257a6
+23
-52
@@ -6,12 +6,9 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.search.DelegatingGlobalSearchScope;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.stubs.StubIndex;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
@@ -26,7 +23,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -46,7 +42,7 @@ public class PyQualifiedNameCompletionMatcher {
|
||||
StubIndex stubIndex = StubIndex.getInstance();
|
||||
Project project = Objects.requireNonNull(scope.getProject());
|
||||
|
||||
GlobalSearchScope moduleMatchingScope = new ModuleQualifiedNameMatchingScope(scope, matcher, project);
|
||||
GlobalSearchScope moduleMatchingScope = scope.intersectWith(new ModuleQualifiedNameMatchingScope(matcher, project));
|
||||
Set<QualifiedName> alreadySuggestedAttributes = new HashSet<>();
|
||||
IndexLookupStats stats = new IndexLookupStats();
|
||||
try {
|
||||
@@ -60,7 +56,7 @@ public class PyQualifiedNameCompletionMatcher {
|
||||
attributeName, project, moduleMatchingScope, idFilter, PyElement.class, element -> {
|
||||
ProgressManager.checkCanceled();
|
||||
VirtualFile vFile = element.getContainingFile().getVirtualFile();
|
||||
QualifiedName moduleQualifiedName = ModuleQualifiedNameMatchingScope.restoreModuleQualifiedName(vFile, project);
|
||||
QualifiedName moduleQualifiedName = findQualifiedNameInClosestRoot(vFile, project);
|
||||
assert moduleQualifiedName != null : vFile;
|
||||
QualifiedName canonicalImportPath = findCanonicalImportPath(element, moduleQualifiedName, currentFile);
|
||||
QualifiedName importPath;
|
||||
@@ -196,57 +192,32 @@ public class PyQualifiedNameCompletionMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
private static class ModuleQualifiedNameMatchingScope extends DelegatingGlobalSearchScope {
|
||||
private static class ModuleQualifiedNameMatchingScope extends QualifiedNameFinder.QualifiedNameBasedScope {
|
||||
private final QualifiedNameMatcher myQualifiedNameMatcher;
|
||||
private final Project myProject;
|
||||
|
||||
ModuleQualifiedNameMatchingScope(@NotNull GlobalSearchScope baseScope,
|
||||
@NotNull QualifiedNameMatcher qualifiedNameMatcher,
|
||||
@NotNull Project project) {
|
||||
super(baseScope);
|
||||
ModuleQualifiedNameMatchingScope(@NotNull QualifiedNameMatcher qualifiedNameMatcher, @NotNull Project project) {
|
||||
super(project);
|
||||
myQualifiedNameMatcher = qualifiedNameMatcher;
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@NotNull VirtualFile file) {
|
||||
if (!super.contains(file)) return false;
|
||||
QualifiedName qualifiedName = restoreModuleQualifiedName(file, myProject);
|
||||
if (qualifiedName == null) return false;
|
||||
return myQualifiedNameMatcher.qualifierMatches(qualifiedName);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static QualifiedName restoreModuleQualifiedName(@NotNull VirtualFile vFile, @NotNull Project project) {
|
||||
ProjectFileIndex projectFileIndex = ProjectFileIndex.SERVICE.getInstance(project);
|
||||
String fileName = vFile.getName();
|
||||
VirtualFile nameAnchor = fileName.equals(PyNames.INIT_DOT_PY) || fileName.equals(PyNames.INIT_DOT_PYI) ? vFile.getParent() : vFile;
|
||||
VirtualFile closestRoot = findClosestRoot(nameAnchor, projectFileIndex);
|
||||
if (closestRoot == null) return null;
|
||||
String relativePath = VfsUtilCore.getRelativePath(nameAnchor, closestRoot);
|
||||
// A relative path can be empty in case of __init__.py directly inside a root.
|
||||
if (relativePath == null || relativePath.isEmpty()) return null;
|
||||
return convertPathToImportableQualifiedName(relativePath);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static QualifiedName convertPathToImportableQualifiedName(@NotNull String relativePath) {
|
||||
List<String> parts = StringUtil.split(relativePath, VfsUtilCore.VFS_SEPARATOR);
|
||||
String fileName = parts.get(parts.size() - 1);
|
||||
parts.set(parts.size() - 1, StringUtil.substringBeforeLast(fileName, "."));
|
||||
if (ContainerUtil.exists(parts, p -> !PyNames.isIdentifier(p))) return null;
|
||||
return QualifiedName.fromComponents(parts);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static VirtualFile findClosestRoot(@NotNull VirtualFile vFile, @NotNull ProjectFileIndex projectFileIndex) {
|
||||
VirtualFile sourceRoot = projectFileIndex.getSourceRootForFile(vFile);
|
||||
if (sourceRoot != null) return sourceRoot;
|
||||
VirtualFile contentRoot = projectFileIndex.getContentRootForFile(vFile);
|
||||
if (contentRoot != null) return contentRoot;
|
||||
VirtualFile libraryRoot = projectFileIndex.getClassRootForFile(vFile);
|
||||
if (libraryRoot != null) return libraryRoot;
|
||||
return null;
|
||||
protected boolean containsQualifiedNameInRoot(@NotNull VirtualFile root, @NotNull QualifiedName qName) {
|
||||
return ContainerUtil.all(qName.getComponents(), PyNames::isIdentifier) && myQualifiedNameMatcher.qualifierMatches(qName);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static QualifiedName findQualifiedNameInClosestRoot(@NotNull VirtualFile file, @NotNull Project project) {
|
||||
// TODO Come up with a better API for exposing these internals
|
||||
Ref<QualifiedName> result = Ref.create();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
new QualifiedNameFinder.QualifiedNameBasedScope(project) {
|
||||
@Override
|
||||
protected boolean containsQualifiedNameInRoot(@NotNull VirtualFile root, @NotNull QualifiedName qName) {
|
||||
result.set(qName);
|
||||
return true;
|
||||
}
|
||||
}.contains(file);
|
||||
return result.get();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user