Don't suggest print function if Py2 file does not contain corresponding import from future (PY-28103)

This commit is contained in:
Semyon Proshev
2018-04-09 17:49:55 +03:00
parent 687f1160a5
commit 6e0ad4e0c8
2 changed files with 27 additions and 6 deletions
@@ -679,18 +679,25 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
final PyQualifiedExpression element = originalElement != null ? originalElement : myElement;
final PsiElement realContext = PyPsiUtils.getRealContext(element);
// include our own names
final int underscores = PyUtil.getInitialUnderscores(element.getName());
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(element);
final LanguageLevel languageLevel = LanguageLevel.forElement(myElement);
final CompletionVariantsProcessor processor = new CompletionVariantsProcessor(element, e -> {
if (builtinCache.isBuiltin(e)) {
final String name = e instanceof PyElement ? ((PyElement)e).getName() : null;
if (e instanceof PyImportElement) {
return false;
}
if (name != null && PyUtil.getInitialUnderscores(name) == 1) {
final String name = e instanceof PyElement ? ((PyElement)e).getName() : null;
if (PyUtil.getInitialUnderscores(name) == 1) {
return false;
}
if (languageLevel.isPython2() && PyNames.PRINT.equals(name)) {
final PyFile file = PyUtil.as(myElement.getContainingFile(), PyFile.class);
if (file != null && !file.hasImportFromFuture(FutureFeature.PRINT_FUNCTION)) {
return false;
}
}
}
return true;
}, null);
@@ -709,7 +716,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
PyResolveUtil.scopeCrawlUp(processor, builtinsFile, null, null);
}
if (underscores >= 2) {
if (PyUtil.getInitialUnderscores(element.getName()) >= 2) {
// if we're a normal module, add module's attrs
if (realContext.getContainingFile() instanceof PyFile) {
for (String name : PyModuleType.getPossibleInstanceMembers()) {
@@ -718,7 +725,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
}
// if we're inside method, add implicit __class__
if (!LanguageLevel.forElement(myElement).isPython2()) {
if (!languageLevel.isPython2()) {
Optional
.ofNullable(PsiTreeUtil.getParentOfType(myElement, PyFunction.class))
.map(PyFunction::getContainingClass)
@@ -1335,6 +1335,20 @@ public class PythonCompletionTest extends PyTestCase {
runWithLanguageLevel(LanguageLevel.PYTHON34, this::assertSingleVariantInExtendedCompletion);
}
// PY-28103
public void testPrintFunctionWithoutFuture() {
final List<String> suggested = doTestByText("pr<caret>");
assertNotNull(suggested);
assertSameElements(suggested, "print", "property", "repr");
}
// PY-28103
public void testPrintFunctionWithFuture() {
final List<String> suggested = doTestByText("from __future__ import print_function\npr<caret>");
assertNotNull(suggested);
assertSameElements(suggested, "print", "print", "print_function", "property", "repr");
}
private void assertNoVariantsInExtendedCompletion() {
myFixture.copyDirectoryToProject(getTestName(true), "");
myFixture.configureByFile("a.py");