diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index 7a07d436ad31..ac0aeb03faae 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -11,6 +11,7 @@ import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.impl.PyQualifiedName; import com.jetbrains.python.psi.impl.PyTypeProvider; +import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.QualifiedNameFinder; import com.jetbrains.python.psi.types.*; import org.jetbrains.annotations.NotNull; @@ -41,11 +42,23 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { @Override public PyType getReferenceType(@NotNull PsiElement referenceTarget, @NotNull TypeEvalContext context, @Nullable PsiElement anchor) { - if (referenceTarget instanceof PyFunction && - PyNames.NAMEDTUPLE.equals(((PyFunction) referenceTarget).getName()) && - PyNames.COLLECTIONS_PY.equals(referenceTarget.getContainingFile().getName()) && - anchor instanceof PyCallExpression) { - return PyNamedTupleType.fromCall((PyCallExpression)anchor); + if (referenceTarget instanceof PyTargetExpression) { + final PyTargetExpression target = (PyTargetExpression)referenceTarget; + final PyQualifiedName calleeName = target.getCalleeName(); + if (calleeName != null && PyNames.NAMEDTUPLE.equals(calleeName.toString())) { + // TODO: Create stubs for namedtuple for preventing switch from stub to AST + final PyExpression value = target.findAssignedValue(); + if (value instanceof PyCallExpression) { + final PyCallExpression call = (PyCallExpression)value; + final PyCallExpression.PyMarkedCallee callee = call.resolveCallee(PyResolveContext.noImplicits()); + if (callee != null) { + final Callable callable = callee.getCallable(); + if (PyNames.COLLECTIONS_PY.equals(callable.getContainingFile().getName())) { + return PyNamedTupleType.fromCall(call); + } + } + } + } } return null; } diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java new file mode 100644 index 000000000000..0d539c1da4e9 --- /dev/null +++ b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java @@ -0,0 +1,39 @@ +package com.jetbrains.python.inspections; + +import com.intellij.testFramework.LightProjectDescriptor; +import com.jetbrains.python.fixtures.PyTestCase; +import com.jetbrains.python.psi.LanguageLevel; +import org.jetbrains.annotations.NotNull; + +/** + * @author vlan + */ +public class Py3UnresolvedReferencesInspectionTest extends PyTestCase { + private static final String TEST_DIRECTORY = "inspections/PyUnresolvedReferencesInspection3K/"; + + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return ourPy3Descriptor; + } + + private void doMultiFileTest(@NotNull final String filename, @NotNull LanguageLevel level) { + runWithLanguageLevel(level, new Runnable() { + @Override + public void run() { + final String testName = getTestName(false); + myFixture.copyDirectoryToProject(TEST_DIRECTORY + testName, ""); + myFixture.configureFromTempProjectFile(filename); + myFixture.enableInspections(PyUnresolvedReferencesInspection.class); + myFixture.checkHighlighting(true, false, false); + } + }); + } + + private void doMultiFileTest(@NotNull String filename) { + doMultiFileTest(filename, LanguageLevel.PYTHON33); + } + + public void testNamedTupleStub() { + doMultiFileTest("a.py"); + } +}