Don't collect imported with as elements as named elements (PY-21837)

Because such elements are not presented in stub.
This commit is contained in:
Semyon Proshev
2018-04-09 17:51:35 +03:00
parent 049ccfa6fe
commit a6c795551c
5 changed files with 54 additions and 16 deletions
@@ -67,15 +67,13 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression {
private ExportedNameCache(long modificationStamp) {
myModificationStamp = modificationStamp;
processDeclarations(PyPsiUtils.collectAllStubChildren(PyFileImpl.this, getStub()), element -> {
if (element instanceof PsiNamedElement && !(element instanceof PyKeywordArgument)) {
final StubElement stub = getStub();
processDeclarations(PyPsiUtils.collectAllStubChildren(PyFileImpl.this, stub), element -> {
if (element instanceof PsiNamedElement &&
!(element instanceof PyKeywordArgument) &&
!(stub == null && element.getParent() instanceof PyImportElement)) {
final PsiNamedElement namedElement = (PsiNamedElement)element;
final String name = namedElement.getName();
if (!myNamedElements.containsKey(name)) {
myNamedElements.put(name, Lists.newArrayList());
}
final List<PsiNamedElement> elements = myNamedElements.get(name);
elements.add(namedElement);
myNamedElements.computeIfAbsent(namedElement.getName(), __ -> new ArrayList<>()).add(namedElement);
}
if (element instanceof PyImportedNameDefiner) {
myImportedNameDefiners.add((PyImportedNameDefiner)element);
@@ -758,13 +756,6 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression {
return newElement;
}
private static class ArrayListThreadLocal extends ThreadLocal<List<String>> {
@Override
protected List<String> initialValue() {
return new ArrayList<>();
}
}
@Override
public ItemPresentation getPresentation() {
return new ItemPresentation() {
@@ -0,0 +1,3 @@
class A(object):
def __init__(self, x): # <- Has argument x
self.x = x
@@ -0,0 +1,9 @@
from A import A as myA # No problem without the 'as'
class B(object):
pass
class C(myA, B): # No problem when only inheriting from myA
pass
@@ -0,0 +1,10 @@
from BC import C # No problem if D is also in BC.py
class D(C):
def __init__(self, x):
C.__init__(self, x) # <- "Unexpected argument" warning for x
d = D(4)
assert d.x == 4 # runs fine
@@ -15,10 +15,15 @@
*/
package com.jetbrains.python.codeInsight;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.types.PyClassLikeType;
import com.jetbrains.python.psi.types.PyClassType;
import com.jetbrains.python.psi.types.PyType;
@@ -162,8 +167,28 @@ public class PyClassMROTest extends PyTestCase {
});
}
// PY-21837
public void testClassImportedFromUnstubbedFileAndSuperImportedWithAs() {
myFixture.copyDirectoryToProject("codeInsight/classMRO/" + getTestName(false), "");
final VirtualFile d = myFixture.findFileInTempDir("D.py");
final VirtualFile bc = myFixture.findFileInTempDir("BC.py");
final PyFile dPsi = (PyFile)myFixture.getPsiManager().findFile(d);
final PsiFile bPsi = myFixture.getPsiManager().findFile(bc);
//noinspection ResultOfMethodCallIgnored
bPsi.getNode(); // unstubbing is necessary
final PyClass dClass = dPsi.findTopLevelClass("D");
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), dPsi); // such context is necessary
final List<PyClass> ancestors = dClass.getAncestorClasses(context);
assertOrderedEquals(ContainerUtil.map(ancestors, PyClass::getName), Arrays.asList("C", "A", "B", PyNames.OBJECT));
}
@NotNull
public PyClass getClass(@NotNull String name) {
private PyClass getClass(@NotNull String name) {
myFixture.configureByFile(getPath(getTestName(false)));
final PyClass cls = myFixture.findElementByText(name, PyClass.class);
assertNotNull(cls);