fixed some cases with **kwargs completion (PY-1050)

This commit is contained in:
Dmitry Trofimov
2010-06-11 16:43:01 +04:00
parent 5cb9e92111
commit b62f959845
6 changed files with 76 additions and 12 deletions

View File

@@ -7,7 +7,6 @@ import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.source.resolve.ResolveCache;
@@ -15,8 +14,6 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Icons;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.SortedList;
import com.jetbrains.appengine.util.PythonUtil;
import com.jetbrains.appengine.util.StringUtils;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.psi.*;
@@ -389,15 +386,20 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
final KwArgParameterCollector collector = new KwArgParameterCollector(flags, ret);
def.getParameterList().acceptChildren(collector);
if (collector.hasKwArgs()) {
def.getStatementList().acceptChildren(new KwArgStatementCallCollector(ret, collector.getKwArgs()));
}
if (collector.hasOnlySelfAndKwArgs()) {
KwArgFromStatementCallCollector fromStatementCallCollector = new KwArgFromStatementCallCollector(ret, collector.getKwArgs());
def.getStatementList().acceptChildren(fromStatementCallCollector);
//if (collector.hasOnlySelfAndKwArgs()) {
// nothing interesting besides self and **kwargs, let's look at superclass (PY-778)
final PsiElement superMethod = PySuperMethodsSearch.search(def).findFirst();
if (superMethod instanceof PyFunction) {
addKeywordArgumentVariants((PyFunction)superMethod, ret, visited);
if (fromStatementCallCollector.isKwArgsTransit()) {
final PsiElement superMethod = PySuperMethodsSearch.search(def).findFirst();
if (superMethod instanceof PyFunction) {
addKeywordArgumentVariants((PyFunction)superMethod, ret, visited);
}
}
}
//}
}
private static class KwArgParameterCollector extends PyElementVisitor {
@@ -445,11 +447,12 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
}
}
private static class KwArgStatementCallCollector extends PyElementVisitor {
private static class KwArgFromStatementCallCollector extends PyElementVisitor {
private final List<Object> myRet;
private final PyParameter myKwArgs;
private boolean kwArgsTransit = true;
public KwArgStatementCallCollector(List<Object> ret, @NotNull PyParameter kwArgs) {
public KwArgFromStatementCallCollector(List<Object> ret, @NotNull PyParameter kwArgs) {
myRet = ret;
this.myKwArgs = kwArgs;
}
@@ -478,6 +481,18 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
}
}
}
else if (callName.equals("__init__")) {
kwArgsTransit = false;
for (PyExpression e : node.getArguments()) {
if (e instanceof PyStarArgument) {
PyStarArgument kw = (PyStarArgument)e;
if (myKwArgs.getName().equals(kw.getFirstChild().getNextSibling().getText())) {
kwArgsTransit = true;
break;
}
}
}
}
super.visitPyCallExpression(node);
}
@@ -490,6 +505,14 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
}
}
}
/**
* is name of kwargs parameter the same as transmitted to __init__ call
* @return
*/
public boolean isKwArgsTransit() {
return kwArgsTransit;
}
}
public boolean isSoft() {
@@ -520,7 +543,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
}
// our very own caching resolver
// our very own caching resolver
private static class CachingResolver implements ResolveCache.PolyVariantResolver<PyReferenceImpl> {
public static CachingResolver INSTANCE = new CachingResolver();
@@ -545,6 +568,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
myNesting.get().getAndDecrement();
}
}
}
@Override

View File

@@ -0,0 +1,7 @@
class A:
def __init__(self, first=True, second=False): pass
class B(A):
def __init__(self, **kwargs): A.__init__(self, first=False)
b = B(fir)

View File

@@ -0,0 +1,7 @@
class A:
def __init__(self, first=True, second=False): pass
class B(A):
def __init__(self, **kwargs): A.__init__(self, first=False)
b = B(fir<caret>)

View File

@@ -0,0 +1,9 @@
class A:
def __init__(self, first=True):
pass
class B(A):
def __init__(self, *args, **kwargs):
super(B, self).__init__(*args, **kwargs)
b = B(first=)

View File

@@ -0,0 +1,9 @@
class A:
def __init__(self, first=True):
pass
class B(A):
def __init__(self, *args, **kwargs):
super(B, self).__init__(*args, **kwargs)
b = B(fir<caret>)

View File

@@ -91,6 +91,14 @@ public class PythonCompletionTest extends PyLightFixtureTestCase {
doTest();
}
public void testSuperInitKwParamsNotOnlySelfAndKwArgs() throws Exception { //PY-1050
doTest();
}
public void testSuperInitKwParamsNoCompletion() throws Exception {
doTest();
}
public void testImportModule() throws Exception {
final String testName = "completion/" + getTestName(true);
myFixture.configureByFiles(testName + ".py", "completion/someModule.py");