PY-20279 Fixed: Suggest implicit __class__ inside methods

In PyReferenceImpl add implicit __class__ to lookup variants
This commit is contained in:
Semyon Proshev
2016-11-15 16:05:09 +03:00
parent 8fba7e8988
commit 3b5e051bfe
3 changed files with 69 additions and 9 deletions
@@ -668,12 +668,19 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
if (underscores >= 2) {
// if we're a normal module, add module's attrs
PsiFile f = realContext.getContainingFile();
if (f instanceof PyFile) {
if (realContext.getContainingFile() instanceof PyFile) {
for (String name : PyModuleType.getPossibleInstanceMembers()) {
ret.add(LookupElementBuilder.create(name).withIcon(PlatformIcons.FIELD_ICON));
}
}
// if we're inside method, add implicit __class__
if (LanguageLevel.forElement(myElement).isAtLeast(LanguageLevel.PYTHON30)) {
Optional
.ofNullable(PsiTreeUtil.getParentOfType(myElement, PyFunction.class))
.map(PyFunction::getContainingClass)
.ifPresent(pyClass -> ret.add(LookupElementBuilder.create(PyNames.__CLASS__)));
}
}
ret.addAll(getOriginalElements(processor));
@@ -19,6 +19,8 @@ import com.intellij.codeInsight.completion.impl.CamelHumpMatcher;
import com.intellij.testFramework.LightProjectDescriptor;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.psi.LanguageLevel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -76,7 +78,8 @@ public class Py3CompletionTest extends PyTestCase {
myFixture.checkResultByFile(getTestName(true) + "/a.after.py");
}
private List<String> doTestByText(String text) {
@Nullable
private List<String> doTestByText(@NotNull String text) {
myFixture.configureByText(PythonFileType.INSTANCE, text);
myFixture.completeBasic();
return myFixture.getLookupElementStrings();
@@ -165,6 +168,28 @@ public class Py3CompletionTest extends PyTestCase {
runWithLanguageLevel(LanguageLevel.PYTHON30, this::doTest);
}
// PY-20279
public void testImplicitDunderClass() {
final List<String> inClassMethod = doTestByText("class First:\n" +
" def foo(self):\n" +
" print(__cl<caret>)");
assertNotNull(inClassMethod);
assertContainsElements(inClassMethod, PyNames.__CLASS__);
final List<String> inStaticMethod = doTestByText("class First:\n" +
" @staticmethod\n" +
" def foo():\n" +
" print(__cl<caret>)");
assertNotNull(inStaticMethod);
assertContainsElements(inStaticMethod, PyNames.__CLASS__);
assertNull(doTestByText("class First:\n" +
" print(__cl<caret>)"));
assertNull(doTestByText("def abc():\n" +
" print(__cl<caret>)"));
}
// PY-20770
public void testAsyncGenerator() {
runWithLanguageLevel(
@@ -27,6 +27,7 @@ import com.jetbrains.python.documentation.PyDocumentationSettings;
import com.jetbrains.python.documentation.docstrings.DocStringFormat;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.psi.LanguageLevel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
@@ -50,7 +51,8 @@ public class PythonCompletionTest extends PyTestCase {
myFixture.checkResultByFile(getTestName(true) + "/a.after.py");
}
private List<String> doTestByText(String text) {
@Nullable
private List<String> doTestByText(@NotNull String text) {
myFixture.configureByText(PythonFileType.INSTANCE, text);
myFixture.completeBasic();
return myFixture.getLookupElementStrings();
@@ -893,7 +895,7 @@ public class PythonCompletionTest extends PyTestCase {
public void testFormatStringWithFormatModifier() {
doTest();
}
// PY-3077
public void testPercentStringWithDictLiteralArg() {
doTest();
@@ -903,7 +905,7 @@ public class PythonCompletionTest extends PyTestCase {
public void testPercentStringWithDictCallArg() {
doTest();
}
// PY-3077
public void testPercentStringWithParenDictCallArg() {
doTest();
@@ -918,17 +920,17 @@ public class PythonCompletionTest extends PyTestCase {
public void testPercentStringDictLiteralStringKey() {
doTest();
}
// PY-3077
public void testPercentStringDictCallStringKey() {
doTest();
}
// PY-3077
public void testPercentStringDictLiteralArgument() {
doTest();
}
// PY-19839
public void testPercentStringDictRefKeys() {
final List<String> variants = doTestByFile();
@@ -1015,6 +1017,32 @@ public class PythonCompletionTest extends PyTestCase {
doTest();
}
// PY-20279
public void testImplicitDunderClass() {
final List<String> inClassMethod = doTestByText("class First:\n" +
" def foo(self):\n" +
" print(__cl<caret>)");
assertNotNull(inClassMethod);
assertDoesntContain(inClassMethod, PyNames.__CLASS__);
final List<String> inStaticMethod = doTestByText("class First:\n" +
" @staticmethod\n" +
" def foo():\n" +
" print(__cl<caret>)");
assertNotNull(inStaticMethod);
assertDoesntContain(inStaticMethod, PyNames.__CLASS__);
final List<String> inClass = doTestByText("class First:\n" +
" print(__cl<caret>)");
assertNotNull(inClass);
assertEmpty(inClass);
final List<String> inFunction = doTestByText("def abc():\n" +
" print(__cl<caret>)");
assertNotNull(inFunction);
assertEmpty(inClass);
}
// PY-20768
public void testInitSubclassBuiltinMethod() {
runWithLanguageLevel(LanguageLevel.PYTHON36,