PY-17810 PY-28989 Namespace package modules added to autocompletion

Packages are added to completion results. Common functionality extracted to PyExtendedCompletionContributor.
This commit is contained in:
Anton Bragin
2018-03-28 13:01:13 +03:00
parent a69da3b135
commit a2f194d858
25 changed files with 240 additions and 152 deletions
@@ -2,7 +2,6 @@
package com.jetbrains.python;
import com.google.common.collect.Lists;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.VfsUtilCore;
@@ -10,7 +9,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.PsiTestUtil;
import com.jetbrains.python.codeInsight.PyCustomMember;
import com.jetbrains.python.fixtures.PyMultiFileResolveTestCase;
import com.jetbrains.python.fixtures.PyResolveTestCase;
@@ -438,7 +436,7 @@ public class PyMultiFileResolveTest extends PyMultiFileResolveTestCase {
// PY-18626
public void testManySourceRoots() {
myFixture.copyDirectoryToProject("manySourceRoots", "");
withSourceRoots(Lists.newArrayList(myFixture.findFileInTempDir("root1"), myFixture.findFileInTempDir("root2")), () -> {
runWithSourceRoots(Lists.newArrayList(myFixture.findFileInTempDir("root1"), myFixture.findFileInTempDir("root2")), () -> {
final PsiFile psiFile = myFixture.configureByFile("a.py");
final PsiReference ref = PyResolveTestCase.findReferenceByMarker(psiFile);
assertInstanceOf(ref, PsiPolyVariantReference.class);
@@ -454,7 +452,7 @@ public class PyMultiFileResolveTest extends PyMultiFileResolveTestCase {
// PY-28321
public void testImportManySourceRoots() {
myFixture.copyDirectoryToProject("importManySourceRoots", "");
withSourceRoots(Lists.newArrayList(myFixture.findFileInTempDir("root2"), myFixture.findFileInTempDir("root1")), () -> {
runWithSourceRoots(Lists.newArrayList(myFixture.findFileInTempDir("root2"), myFixture.findFileInTempDir("root1")), () -> {
final PsiFile psiFile = myFixture.configureByFile("root1/pkg/a.py");
final PsiReference ref = PyResolveTestCase.findReferenceByMarker(psiFile);
assertInstanceOf(ref, PsiPolyVariantReference.class);
@@ -470,7 +468,7 @@ public class PyMultiFileResolveTest extends PyMultiFileResolveTestCase {
// PY-28321
public void testImportManySourceRootsReverseRootOrder() {
myFixture.copyDirectoryToProject("importManySourceRoots", "");
withSourceRoots(Lists.newArrayList(myFixture.findFileInTempDir("root1"), myFixture.findFileInTempDir("root2")), () -> {
runWithSourceRoots(Lists.newArrayList(myFixture.findFileInTempDir("root1"), myFixture.findFileInTempDir("root2")), () -> {
final PsiFile psiFile = myFixture.configureByFile("root1/pkg/a.py");
final PsiReference ref = PyResolveTestCase.findReferenceByMarker(psiFile);
assertInstanceOf(ref, PsiPolyVariantReference.class);
@@ -485,7 +483,7 @@ public class PyMultiFileResolveTest extends PyMultiFileResolveTestCase {
VirtualFile vf = myFixture.findFileInTempDir("ext/m1.py");
withSourceRoots(Lists.newArrayList(myFixture.findFileInTempDir("root")), () -> {
runWithSourceRoots(Lists.newArrayList(myFixture.findFileInTempDir("root")), () -> {
final PsiFile extSource = myFixture.getPsiManager().findFile(vf);
PyImportResolver foreignResolver = (name, context, withRoots) -> name.toString().equals("m1") ? extSource : null;
PlatformTestUtil.registerExtension(PyImportResolver.EP_NAME, foreignResolver, getTestRootDisposable());
@@ -10,7 +10,7 @@ import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.testFramework.TestDataPath;
import com.jetbrains.python.documentation.docstrings.DocStringFormat;
import com.jetbrains.python.fixtures.PyMultiFileResolveTestCase;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.psi.LanguageLevel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -21,7 +21,7 @@ import java.util.List;
import java.util.Set;
@TestDataPath("$CONTENT_ROOT/../testData/completion")
public class PythonCompletionTest extends PyMultiFileResolveTestCase {
public class PythonCompletionTest extends PyTestCase {
private void doTest() {
CamelHumpMatcher.forceStartMatching(myFixture.getTestRootDisposable());
@@ -32,9 +32,13 @@ public class PythonCompletionTest extends PyMultiFileResolveTestCase {
}
private void doMultiFileTest() {
doMultiFileTest(CompletionType.BASIC, 1);
}
private void doMultiFileTest(CompletionType completionType, int invocationCount) {
myFixture.copyDirectoryToProject(getTestName(true), "");
myFixture.configureByFile("a.py");
myFixture.completeBasic();
myFixture.complete(completionType, invocationCount);
myFixture.checkResultByFile(getTestName(true) + "/a.after.py");
}
@@ -1288,7 +1292,7 @@ public class PythonCompletionTest extends PyMultiFileResolveTestCase {
// PY-17810
public void testDuplicatedEntriesFromMultipleSourceRoots() {
assertSingleVariantInExtendedCompletion();
assertSingleVariantInExtendedCompletionWithSourceRoots();
}
// PY-17810
@@ -1298,7 +1302,27 @@ public class PythonCompletionTest extends PyMultiFileResolveTestCase {
// PY-17810
public void testModuleFromMultipleSourceRoots() {
assertSingleVariantInExtendedCompletion();
assertSingleVariantInExtendedCompletionWithSourceRoots();
}
// PY-17810
public void testPackageFromMultipleSourceRoots() {
assertSingleVariantInExtendedCompletionWithSourceRoots();
}
// PY-17810
public void testFromPackageImport() {
myFixture.copyDirectoryToProject(getTestName(true), "");
myFixture.configureByFile("a.py");
myFixture.complete(CompletionType.BASIC, 2);
final List<String> suggested = myFixture.getLookupElementStrings();
assertNotNull(suggested);
assertSameElements(suggested, "m1", "m2");
}
// PY-28989
public void testModuleFromNamespacePackage() {
runWithLanguageLevel(LanguageLevel.PYTHON34, this::assertSingleVariantInExtendedCompletion);
}
private void assertNoVariantsInExtendedCompletion() {
@@ -1310,15 +1334,20 @@ public class PythonCompletionTest extends PyMultiFileResolveTestCase {
}
private void assertSingleVariantInExtendedCompletion() {
doMultiFileTest(CompletionType.BASIC, 2);
assertNull(myFixture.getLookupElements());
}
private void assertSingleVariantInExtendedCompletionWithSourceRoots() {
myFixture.copyDirectoryToProject(getTestName(true), "");
withSourceRoots(Lists.newArrayList(
runWithSourceRoots(Lists.newArrayList(
myFixture.findFileInTempDir("root1"),
myFixture.findFileInTempDir("root2")),
() -> {
myFixture.configureByFile("a.py");
myFixture.complete(CompletionType.BASIC, 2);
assertNull(myFixture.getLookupElements());
});
() -> {
myFixture.configureByFile("a.py");
assertNull(myFixture.complete(CompletionType.BASIC, 2));
myFixture.checkResultByFile(getTestName(true) + "/a.after.py");
});
}
@Override
@@ -16,12 +16,10 @@
package com.jetbrains.python.fixtures;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileFilter;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PythonFileType;
import com.jetbrains.python.PythonTestUtil;
@@ -100,13 +98,4 @@ public abstract class PyMultiFileResolveTestCase extends PyResolveTestCase {
return Collections.singletonList(ref.resolve());
}
protected void withSourceRoots(@NotNull List<VirtualFile> sourceRoots, @NotNull Runnable f) {
final Module module = myFixture.getModule();
sourceRoots.forEach(root -> PsiTestUtil.addSourceRoot(module, root));
try {
f.run();
} finally {
sourceRoots.forEach(root -> PsiTestUtil.removeSourceRoot(module, root));
}
}
}
@@ -205,10 +205,10 @@ public abstract class PyTestCase extends UsefulTestCase {
PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), languageLevel);
}
protected void runWithLanguageLevel(@NotNull LanguageLevel languageLevel, @NotNull Runnable action) {
protected void runWithLanguageLevel(@NotNull LanguageLevel languageLevel, @NotNull Runnable runnable) {
setLanguageLevel(languageLevel);
try {
action.run();
runnable.run();
}
finally {
setLanguageLevel(null);
@@ -227,6 +227,16 @@ public abstract class PyTestCase extends UsefulTestCase {
}
}
protected void runWithSourceRoots(@NotNull List<VirtualFile> sourceRoots, @NotNull Runnable runnable) {
final Module module = myFixture.getModule();
sourceRoots.forEach(root -> PsiTestUtil.addSourceRoot(module, root));
try {
runnable.run();
} finally {
sourceRoots.forEach(root -> PsiTestUtil.removeSourceRoot(module, root));
}
}
protected static void assertNotParsed(PsiFile file) {
assertInstanceOf(file, PyFileImpl.class);
assertNull("Operations should have been performed on stubs but caused file to be parsed: " + file.getVirtualFile().getPath(),