mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Resolve to project sources first instead of libraries and stubs (PY-7775).
This commit is contained in:
@@ -533,7 +533,7 @@ class DocumentationBuilder {
|
||||
myPath = path;
|
||||
}
|
||||
|
||||
public boolean visitRoot(VirtualFile root, Module module, Sdk sdk) {
|
||||
public boolean visitRoot(VirtualFile root, Module module, Sdk sdk, boolean isModuleSource) {
|
||||
String vpath = VfsUtil.urlToPath(root.getUrl());
|
||||
if (myPath.startsWith(vpath)) {
|
||||
myResult = vpath;
|
||||
|
||||
@@ -125,11 +125,13 @@ public class QualifiedNameFinder {
|
||||
|
||||
/**
|
||||
* Tries to find roots that contain given vfile, and among them the root that contains at the smallest depth.
|
||||
* For equal depth source root is in preference to library.
|
||||
*/
|
||||
private static class PathChoosingVisitor implements RootVisitor {
|
||||
|
||||
private final VirtualFile myVFile;
|
||||
private List<String> myResult;
|
||||
private boolean myIsModuleSource;
|
||||
|
||||
private PathChoosingVisitor(VirtualFile file) {
|
||||
if (!file.isDirectory() && file.getName().equals(PyNames.INIT_DOT_PY)) {
|
||||
@@ -140,11 +142,11 @@ public class QualifiedNameFinder {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean visitRoot(VirtualFile root, Module module, Sdk sdk) {
|
||||
public boolean visitRoot(VirtualFile root, Module module, Sdk sdk, boolean isModuleSource) {
|
||||
final String relativePath = VfsUtilCore.getRelativePath(myVFile, root, '/');
|
||||
if (relativePath != null) {
|
||||
List<String> result = StringUtil.split(relativePath, "/");
|
||||
if (myResult == null || result.size() < myResult.size()) {
|
||||
if (myResult == null || result.size() < myResult.size() || (isModuleSource && !myIsModuleSource)) {
|
||||
if (result.size() > 0) {
|
||||
result.set(result.size() - 1, FileUtil.getNameWithoutExtension(result.get(result.size() - 1)));
|
||||
}
|
||||
@@ -154,6 +156,7 @@ public class QualifiedNameFinder {
|
||||
}
|
||||
}
|
||||
myResult = result;
|
||||
myIsModuleSource = isModuleSource;
|
||||
}
|
||||
}
|
||||
return myResult == null || myResult.size() > 0;
|
||||
|
||||
@@ -36,7 +36,8 @@ public class QualifiedNameResolverImpl implements RootVisitor, QualifiedNameReso
|
||||
boolean myCheckForPackage = true;
|
||||
private final QualifiedNameResolveContext myContext = new QualifiedNameResolveContext();
|
||||
private final @NotNull PyQualifiedName myQualifiedName;
|
||||
final Set<PsiElement> results = Sets.newLinkedHashSet();
|
||||
final Set<PsiElement> mySourceResults = Sets.newLinkedHashSet();
|
||||
final Set<PsiElement> myLibResults = Sets.newLinkedHashSet();
|
||||
private boolean myVisitAllModules = false;
|
||||
private int myRelativeLevel = -1;
|
||||
private boolean myWithoutRoots;
|
||||
@@ -102,7 +103,7 @@ public class QualifiedNameResolverImpl implements RootVisitor, QualifiedNameReso
|
||||
|
||||
/**
|
||||
* Specifies whether we should attempt to resolve imports relative to the current file.
|
||||
*
|
||||
*
|
||||
* @param relativeLevel if >= 0, we try to resolve at the specified number of levels above the current file.
|
||||
* @return this
|
||||
*/
|
||||
@@ -140,26 +141,35 @@ public class QualifiedNameResolverImpl implements RootVisitor, QualifiedNameReso
|
||||
myCheckForPackage = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean visitRoot(final VirtualFile root, @Nullable Module module, @Nullable Sdk sdk) {
|
||||
|
||||
public boolean visitRoot(final VirtualFile root, @Nullable Module module, @Nullable Sdk sdk, boolean isModuleSource) {
|
||||
if (!root.isValid()) {
|
||||
return true;
|
||||
}
|
||||
PsiFileSystemItem resolveResult = resolveInRoot(root);
|
||||
if (resolveResult != null) {
|
||||
results.add(resolveResult);
|
||||
addRoot(resolveResult, isModuleSource);
|
||||
}
|
||||
|
||||
if (isAcceptRootAsTopLevelPackage() && myQualifiedName.matchesPrefix(PyQualifiedName.fromDottedString(root.getName()))) {
|
||||
resolveResult = resolveInRoot(root.getParent());
|
||||
if (resolveResult != null) {
|
||||
results.add(resolveResult);
|
||||
addRoot(resolveResult, isModuleSource);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addRoot(PsiFileSystemItem resolveResult, boolean isModuleSource) {
|
||||
if (isModuleSource) {
|
||||
mySourceResults.add(resolveResult);
|
||||
}
|
||||
else {
|
||||
myLibResults.add(resolveResult);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<PsiElement> resultsAsList() {
|
||||
@@ -177,24 +187,27 @@ public class QualifiedNameResolverImpl implements RootVisitor, QualifiedNameReso
|
||||
|
||||
PsiFileSystemItem module = resolveModuleAt(dir);
|
||||
if (module != null) {
|
||||
results.add(module);
|
||||
addRoot(module, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!myWithoutRoots) {
|
||||
results.addAll(resolveInRoots());
|
||||
mySourceResults.addAll(resolveInRoots());
|
||||
}
|
||||
|
||||
if (!myWithoutForeign) {
|
||||
for (PyImportResolver resolver : Extensions.getExtensions(PyImportResolver.EP_NAME)) {
|
||||
PsiElement foreign = resolver.resolveImportReference(myQualifiedName, myContext);
|
||||
if (foreign != null) {
|
||||
results.add(foreign);
|
||||
mySourceResults.add(foreign);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Lists.newArrayList(results);
|
||||
mySourceResults.addAll(myLibResults);
|
||||
myLibResults.clear();
|
||||
|
||||
return Lists.newArrayList(mySourceResults);
|
||||
}
|
||||
|
||||
private List<PsiElement> resolveInRoots() {
|
||||
@@ -228,7 +241,9 @@ public class QualifiedNameResolverImpl implements RootVisitor, QualifiedNameReso
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
final ArrayList<PsiElement> resultList = Lists.newArrayList(results);
|
||||
mySourceResults.addAll(myLibResults);
|
||||
myLibResults.clear();
|
||||
final ArrayList<PsiElement> resultList = Lists.newArrayList(mySourceResults);
|
||||
if (cache != null) {
|
||||
cache.put(myQualifiedName, resultList);
|
||||
}
|
||||
@@ -249,18 +264,18 @@ public class QualifiedNameResolverImpl implements RootVisitor, QualifiedNameReso
|
||||
for (PsiElement element : resultsAsList()) {
|
||||
if (clazz.isInstance(element)) {
|
||||
//noinspection unchecked
|
||||
result.add((T) element);
|
||||
result.add((T)element);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <T extends PsiElement> T firstResultOfType(Class<T> clazz) {
|
||||
final List<T> list = resultsOfType(clazz);
|
||||
return list.size() > 0 ? list.get(0) : null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean withOtherSdk() {
|
||||
return myContext.getSdk() != null && myContext.getSdk() != PythonSdkType.findPythonSdk(myContext.getModule());
|
||||
@@ -307,9 +322,8 @@ public class QualifiedNameResolverImpl implements RootVisitor, QualifiedNameReso
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
seeker = (PsiFileSystemItem) ResolveImportUtil.resolveChild(seeker, name, myContext.getFootholdFile(), true, myCheckForPackage);
|
||||
seeker = (PsiFileSystemItem)ResolveImportUtil.resolveChild(seeker, name, myContext.getFootholdFile(), true, myCheckForPackage);
|
||||
}
|
||||
return seeker;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,5 +18,5 @@ public interface RootVisitor {
|
||||
*
|
||||
* @return false when visiting must stop.
|
||||
*/
|
||||
boolean visitRoot(VirtualFile root, @Nullable Module module, @Nullable Sdk sdk);
|
||||
boolean visitRoot(VirtualFile root, @Nullable Module module, @Nullable Sdk sdk, boolean isModuleSource);
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public class RootVisitorHost {
|
||||
public static boolean visitSdkRoots(@NotNull Sdk sdk, @NotNull RootVisitor visitor) {
|
||||
final VirtualFile[] roots = sdk.getRootProvider().getFiles(OrderRootType.CLASSES);
|
||||
for (VirtualFile root : roots) {
|
||||
if (!visitor.visitRoot(root, null, sdk)) {
|
||||
if (!visitor.visitRoot(root, null, sdk, false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -92,10 +92,10 @@ public class RootVisitorHost {
|
||||
for (ContentEntry entry : rootModel.getContentEntries()) {
|
||||
VirtualFile rootFile = entry.getFile();
|
||||
|
||||
if (rootFile != null && !visitor.visitRoot(rootFile, null, null)) return false;
|
||||
if (rootFile != null && !visitor.visitRoot(rootFile, null, null, true)) return false;
|
||||
contentRoots.add(rootFile);
|
||||
for (VirtualFile folder : entry.getSourceFolderFiles()) {
|
||||
if (!visitor.visitRoot(folder, rootModel.getModule(), null)) return false;
|
||||
if (!visitor.visitRoot(folder, rootModel.getModule(), null, true)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -108,7 +108,7 @@ public class RootVisitorHost {
|
||||
Module module = entry instanceof ModuleOrderEntry ? ((ModuleOrderEntry) entry).getModule() : null;
|
||||
Sdk sdk = entry instanceof JdkOrderEntry ? ((JdkOrderEntry) entry).getJdk() : null;
|
||||
for (VirtualFile root : allRoots) {
|
||||
if (!visitor.visitRoot(root, module, sdk)) {
|
||||
if (!visitor.visitRoot(root, module, sdk, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import re
|
||||
|
||||
re.foobar()
|
||||
# <ref>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#re module in project sources
|
||||
|
||||
def foobar():
|
||||
pass
|
||||
@@ -26,7 +26,7 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
|
||||
public void testSimple() {
|
||||
PsiElement element = doResolve();
|
||||
assertTrue(element instanceof PyFile);
|
||||
assertEquals("ImportedFile.py", ((PyFile) element).getName());
|
||||
assertEquals("ImportedFile.py", ((PyFile)element).getName());
|
||||
}
|
||||
|
||||
public void testFromImport() {
|
||||
@@ -34,7 +34,7 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
|
||||
assertTrue(results.length == 2); // func and import stmt
|
||||
PsiElement func_elt = results[0].getElement();
|
||||
assertTrue("is PyFunction?", func_elt instanceof PyFunction);
|
||||
assertEquals("named 'func'?", "func", ((PyFunction) func_elt).getName());
|
||||
assertEquals("named 'func'?", "func", ((PyFunction)func_elt).getName());
|
||||
PsiElement import_elt = results[1].getElement();
|
||||
assertTrue("is import?", import_elt instanceof PyImportElement);
|
||||
}
|
||||
@@ -44,7 +44,7 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
|
||||
assertTrue(results.length == 2); // func and import-* stmt
|
||||
PsiElement func_elt = results[0].getElement();
|
||||
assertTrue("is PyFunction?", func_elt instanceof PyFunction);
|
||||
assertEquals("named 'func'?", "func", ((PyFunction) func_elt).getName());
|
||||
assertEquals("named 'func'?", "func", ((PyFunction)func_elt).getName());
|
||||
PsiElement import_elt = results[1].getElement();
|
||||
assertTrue("is import?", import_elt instanceof PyStarImportElement);
|
||||
}
|
||||
@@ -57,7 +57,7 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
|
||||
public void testFromPackageImportFile() {
|
||||
PsiElement element = doResolve();
|
||||
assertTrue(element instanceof PsiFile);
|
||||
assertEquals("myfile.py", ((PyFile) element).getName());
|
||||
assertEquals("myfile.py", ((PyFile)element).getName());
|
||||
}
|
||||
|
||||
public void testFromQualifiedPackageImport() {
|
||||
@@ -68,20 +68,20 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
|
||||
public void testFromQualifiedFileImportClass() {
|
||||
PsiElement element = doResolve();
|
||||
assertTrue(element instanceof PsiFile);
|
||||
assertEquals("myfile.py", ((PsiFile) element).getName());
|
||||
assertEquals("mypackage", ((PsiFile) element).getContainingDirectory().getName());
|
||||
assertEquals("myfile.py", ((PsiFile)element).getName());
|
||||
assertEquals("mypackage", ((PsiFile)element).getContainingDirectory().getName());
|
||||
}
|
||||
|
||||
public void testImportAs() {
|
||||
PsiElement element = doResolve();
|
||||
assertTrue(element instanceof PyFunction);
|
||||
assertEquals("func", ((PyFunction) element).getName());
|
||||
assertEquals("func", ((PyFunction)element).getName());
|
||||
}
|
||||
|
||||
public void testFromQualifiedPackageImportFile() {
|
||||
PsiElement element = doResolve();
|
||||
assertTrue(element instanceof PsiFile);
|
||||
assertEquals("testfile.py", ((PsiFile) element).getName());
|
||||
assertEquals("testfile.py", ((PsiFile)element).getName());
|
||||
}
|
||||
|
||||
public void testFromInitPyImportFunction() {
|
||||
@@ -101,7 +101,7 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
|
||||
final PsiFile psiFile = myFixture.configureByFile("pack/__init__.py");
|
||||
final PsiElement result = doResolve(psiFile);
|
||||
assertInstanceOf(result, PyFile.class);
|
||||
assertEquals("mod.py", ((PyFile) result).getName());
|
||||
assertEquals("mod.py", ((PyFile)result).getName());
|
||||
}
|
||||
|
||||
public void testResolveInPkg() {
|
||||
@@ -109,7 +109,7 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
|
||||
assertTrue(results.length == 2); // func and import stmt
|
||||
PsiElement func_elt = results[0].getElement();
|
||||
assertTrue("is PyFunction?", func_elt instanceof PyFunction);
|
||||
assertEquals("named 'token'?", "token", ((PyFunction) func_elt).getName());
|
||||
assertEquals("named 'token'?", "token", ((PyFunction)func_elt).getName());
|
||||
PsiElement import_elt = results[1].getElement();
|
||||
assertTrue("is import?", import_elt instanceof PyImportElement);
|
||||
}
|
||||
@@ -186,7 +186,7 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
|
||||
PsiElement element = doResolve();
|
||||
element = element.getNavigationElement();
|
||||
assertInstanceOf(element, PyFile.class);
|
||||
assertEquals("__init__.py", ((PyFile) element).getName());
|
||||
assertEquals("__init__.py", ((PyFile)element).getName());
|
||||
}
|
||||
|
||||
public void testImportOsPath() {
|
||||
@@ -405,7 +405,8 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
|
||||
setLanguageLevel(LanguageLevel.PYTHON33);
|
||||
try {
|
||||
assertResolvesTo(PsiDirectory.class, "p1");
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
setLanguageLevel(null);
|
||||
}
|
||||
}
|
||||
@@ -415,11 +416,18 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
|
||||
setLanguageLevel(LanguageLevel.PYTHON33);
|
||||
try {
|
||||
assertResolvesTo(PyFunction.class, "foo");
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
setLanguageLevel(null);
|
||||
}
|
||||
}
|
||||
|
||||
// PY-7775
|
||||
public void testProjectSourcesFirst() {
|
||||
myTestFileName = "mod/" + getTestName(false) + ".py";
|
||||
assertResolvesTo(PyFunction.class, "foobar");
|
||||
}
|
||||
|
||||
private void prepareTestDirectory() {
|
||||
final String testName = getTestName(true);
|
||||
myFixture.copyDirectoryToProject(testName, "");
|
||||
@@ -429,7 +437,7 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
|
||||
private PsiFile prepareFile() {
|
||||
prepareTestDirectory();
|
||||
VirtualFile sourceFile = null;
|
||||
for (String ext : new String[] {".py", ".pyx"}) {
|
||||
for (String ext : new String[]{".py", ".pyx"}) {
|
||||
final String fileName = myTestFileName != null ? myTestFileName : getTestName(false) + ext;
|
||||
sourceFile = myFixture.findFileInTempDir(fileName);
|
||||
if (sourceFile != null) {
|
||||
@@ -460,7 +468,7 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
|
||||
if (resolveResults.length == 0) {
|
||||
return null;
|
||||
}
|
||||
return resolveResults[0].isValidResult() ? resolveResults [0].getElement() : null;
|
||||
return resolveResults[0].isValidResult() ? resolveResults[0].getElement() : null;
|
||||
}
|
||||
finally {
|
||||
psiManager.setAssertOnFileLoadingFilter(VirtualFileFilter.NONE);
|
||||
|
||||
Reference in New Issue
Block a user