PY-24450 Suggest importing modules for unresolved decorators without arguments

Because it can be just an incomplete qualified name of the needed callable.
This commit is contained in:
Mikhail Golubev
2018-08-15 12:44:23 +03:00
parent 0c9242fdbc
commit 58a25d2c34
7 changed files with 40 additions and 6 deletions
@@ -212,8 +212,11 @@ public final class PythonImportUtils {
}
private static boolean isPossibleModuleReference(PyElement node) {
if (node.getParent() instanceof PyCallExpression && node == ((PyCallExpression) node.getParent()).getCallee()) {
return false;
final PyCallExpression callExpression = as(node.getParent(), PyCallExpression.class);
if (callExpression != null && node == callExpression.getCallee()) {
final PyDecorator decorator = as(callExpression, PyDecorator.class);
// getArgumentList() still returns empty (but not null) element in this case
return decorator != null && !decorator.hasArgumentList();
}
if (node.getParent() instanceof PyArgumentList) {
final PyArgumentList argumentList = (PyArgumentList)node.getParent();
@@ -0,0 +1,3 @@
@<error descr="Unresolved reference 'pytest'">py<caret>test</error>
def test_skipped():
pass
@@ -0,0 +1,6 @@
import pytest
@pytest
def test_skipped():
pass
@@ -0,0 +1,3 @@
@<error descr="Unresolved reference 'pytest'">py<caret>test</error>()
def test_skipped():
pass
@@ -119,15 +119,22 @@ public class PyAddImportQuickFixTest extends PyQuickFixTestCase {
doMultiFileAutoImportTest("Import 'ClassB from foo.bar.baz'");
}
// PY-24450
public void testAvailableForUnqualifiedDecoratorWithoutArguments() {
doMultiFileAutoImportTest("Import 'pytest'");
}
// PY-24450
public void testUnavailableForUnqualifiedDecoratorWithArguments() {
doMultiFileNegativeTest("Import 'pytest'");
}
private void doMultiFileAutoImportTest(@NotNull String hintPrefix) {
doMultiFileAutoImportTest(hintPrefix, null);
}
private void doMultiFileAutoImportTest(@NotNull String hintPrefix, @Nullable Processor<AutoImportQuickFix> checkQuickfix) {
myFixture.copyDirectoryToProject(getTestName(true), "");
myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
myFixture.configureByFile("main.py");
myFixture.checkHighlighting(true, false, false);
configureMultiFileProject();
final PsiElement hostUnderCaret = myFixture.getFile().findElementAt(myFixture.getCaretOffset());
final PyReferenceExpression hostRefExpr = PsiTreeUtil.getParentOfType(hostUnderCaret, PyReferenceExpression.class);
@@ -147,4 +154,16 @@ public class PyAddImportQuickFixTest extends PyQuickFixTestCase {
myFixture.checkResultByFile(getTestName(true) + "/main_after.py", true);
}
}
private void doMultiFileNegativeTest(@NotNull String hintPrefix) {
configureMultiFileProject();
assertEmpty(myFixture.filterAvailableIntentions(hintPrefix));
}
private void configureMultiFileProject() {
myFixture.copyDirectoryToProject(getTestName(true), "");
myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
myFixture.configureByFile("main.py");
myFixture.checkHighlighting(true, false, false);
}
}