Restored None, False, True as non-keywords (reserved words) in PY2 (PY-23305, PY-23364)

Typeshed doesn't contain the definitions for them in __builtins__.pyi
so we have to provide types and detect the builtin status for these
words as a special case.
This commit is contained in:
Andrey Vlasovskikh
2017-04-07 19:14:20 +03:00
committed by Andrey Vlasovskikh
parent 859ed8fb1c
commit 91a45bf7ed
15 changed files with 70 additions and 36 deletions

View File

@@ -82,6 +82,21 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
return null;
}
@Nullable
@Override
public PyType getReferenceExpressionType(@NotNull PyReferenceExpression referenceExpression, @NotNull TypeEvalContext context) {
if (!referenceExpression.isQualified()) {
final String name = referenceExpression.getReferencedName();
if (PyNames.NONE.equals(name)) {
return PyNoneType.INSTANCE;
}
else if (PyNames.FALSE.equals(name) || PyNames.TRUE.equals(name)) {
return PyBuiltinCache.getInstance(referenceExpression).getBoolType();
}
}
return null;
}
@Nullable
private static PyType getBaseStringType(@NotNull PsiElement referenceTarget) {
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(referenceTarget);

View File

@@ -149,18 +149,23 @@ public class PyArgumentEqualDefaultInspection extends PyInspection {
if (((PyStringLiteralExpression)key).getStringValue().equals(((PyStringLiteralExpression)defaultValue).getStringValue()))
return true;
}
else if (key instanceof PyReferenceExpression && PyUtil.isPy2ReservedWord((PyReferenceExpression)key) &&
key.getText().equals(defaultValue.getText())) {
return true;
}
else {
PsiReference keyRef = key instanceof PyReferenceExpression
? ((PyReferenceExpression) key).getReference(getResolveContext())
PsiReference keyRef = key instanceof PyReferenceExpression
? ((PyReferenceExpression)key).getReference(getResolveContext())
: key.getReference();
PsiReference defRef = defaultValue instanceof PyReferenceExpression
? ((PyReferenceExpression) defaultValue).getReference(getResolveContext())
? ((PyReferenceExpression)defaultValue).getReference(getResolveContext())
: defaultValue.getReference();
if (keyRef != null && defRef != null) {
PsiElement keyResolve = keyRef.resolve();
PsiElement defResolve = defRef.resolve();
if (keyResolve != null && keyResolve.equals(defResolve))
if (keyResolve != null && keyResolve.equals(defResolve)) {
return true;
}
}
}
return false;

View File

@@ -23,6 +23,7 @@ import com.jetbrains.python.PyBundle;
import com.jetbrains.python.codeInsight.stdlib.PyNamedTupleType;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import com.jetbrains.python.psi.types.PyNoneType;
import com.jetbrains.python.psi.types.PyTupleType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.TypeEvalContext;
@@ -112,6 +113,9 @@ public class PyTupleAssignmentBalanceInspection extends PyInspection {
else if (assignedType instanceof PyNamedTupleType) {
return ((PyNamedTupleType)assignedType).getElementCount();
}
else if (assignedType instanceof PyNoneType) {
return 1;
}
return -1;
}

View File

@@ -69,10 +69,6 @@ public class PythonHighlightingLexer extends PythonLexer {
if (tokenType == PyTokenTypes.IDENTIFIER) {
final String tokenText = getTokenText();
if (tokenText.equals("None")) return PyTokenTypes.NONE_KEYWORD;
if (tokenText.equals("True")) return PyTokenTypes.TRUE_KEYWORD;
if (tokenText.equals("False")) return PyTokenTypes.FALSE_KEYWORD;
if (myLanguageLevel.hasWithStatement()) {
if (tokenText.equals("with")) return PyTokenTypes.WITH_KEYWORD;
if (tokenText.equals("as")) return PyTokenTypes.AS_KEYWORD;
@@ -83,6 +79,9 @@ public class PythonHighlightingLexer extends PythonLexer {
}
if (myLanguageLevel.isPy3K()) {
if (tokenText.equals("None")) return PyTokenTypes.NONE_KEYWORD;
if (tokenText.equals("True")) return PyTokenTypes.TRUE_KEYWORD;
if (tokenText.equals("False")) return PyTokenTypes.FALSE_KEYWORD;
if (tokenText.equals("nonlocal")) return PyTokenTypes.NONLOCAL_KEYWORD;
if (tokenText.equals("__debug__")) return PyTokenTypes.DEBUG_KEYWORD;
}

View File

@@ -927,16 +927,16 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
isWordAtPosition(text, start, end, TOK_PRINT)) {
return PyTokenTypes.PRINT_KEYWORD;
}
else if (source == PyTokenTypes.IDENTIFIER && isWordAtPosition(text, start, end, TOK_NONE)) {
return PyTokenTypes.NONE_KEYWORD;
}
else if (source == PyTokenTypes.IDENTIFIER && isWordAtPosition(text, start, end, TOK_TRUE)) {
return PyTokenTypes.TRUE_KEYWORD;
}
else if (source == PyTokenTypes.IDENTIFIER && isWordAtPosition(text, start, end, TOK_FALSE)) {
return PyTokenTypes.FALSE_KEYWORD;
}
else if (myContext.getLanguageLevel().isPy3K() && source == PyTokenTypes.IDENTIFIER) {
if (isWordAtPosition(text, start, end, TOK_NONE)) {
return PyTokenTypes.NONE_KEYWORD;
}
if (isWordAtPosition(text, start, end, TOK_TRUE)) {
return PyTokenTypes.TRUE_KEYWORD;
}
if (isWordAtPosition(text, start, end, TOK_FALSE)) {
return PyTokenTypes.FALSE_KEYWORD;
}
if (isWordAtPosition(text, start, end, TOK_DEBUG)) {
return PyTokenTypes.DEBUG_KEYWORD;
}

View File

@@ -910,6 +910,18 @@ public class PyUtil {
return as(PyPsiUtils.getPrevNonWhitespaceSibling(statementList), PsiComment.class);
}
public static boolean isPy2ReservedWord(@NotNull PyReferenceExpression node) {
if (LanguageLevel.forElement(node).isOlderThan(LanguageLevel.PYTHON30)) {
if (!node.isQualified()) {
final String name = node.getName();
if (PyNames.NONE.equals(name) || PyNames.FALSE.equals(name) || PyNames.TRUE.equals(name)) {
return true;
}
}
}
return false;
}
/**
* Retrieve the document from {@link PsiDocumentManager} using the anchor PSI element and pass it to the consumer function
* first releasing it from pending PSI modifications it with {@link PsiDocumentManager#doPostponedOperationsAndUnblockDocument(Document)}

View File

@@ -228,10 +228,6 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
try {
final boolean qualified = isQualified();
if (!qualified && PyNames.NONE.equals(getReferencedName())) {
return PyNoneType.INSTANCE;
}
final PyType providedType = getTypeFromProviders(context);
if (providedType != null) {
return providedType;

View File

@@ -37,7 +37,10 @@ public class PyBuiltinAnnotator extends PyAnnotator {
final String name = node.getName();
if (name == null) return;
final boolean highlightedAsAttribute = highlightAsAttribute(node, name);
if (!highlightedAsAttribute && PyBuiltinCache.isInBuiltins(node)) {
if (highlightedAsAttribute) {
return;
}
if (PyBuiltinCache.isInBuiltins(node) || PyUtil.isPy2ReservedWord(node)) {
final Annotation ann;
final PsiElement parent = node.getParent();
if (parent instanceof PyDecorator) {

View File

@@ -14,4 +14,4 @@ class <info descr="null" type="INFORMATION" foreground="0x0000ff" background="0x
pass
def <info descr="null" type="INFORMATION" foreground="0xff0000" background="0x000000" effectcolor="0xffffff" effecttype="BOXED" fonttype="1">__made_up__</info>(<info descr="null">self</info>):
return None
return <info type="INFORMATION">None</info>

View File

@@ -2,4 +2,4 @@
def <info descr="null" type="INFORMATION" foreground="0xff0000" background="0x000000" effectcolor="0xffffff" effecttype="BOXED" fonttype="1">foo</info>():
def <info descr="null" type="INFORMATION" foreground="0xff0000" background="0x000000" effectcolor="0xffffff" effecttype="BOXED" fonttype="1">a</info>():
yield 1
return False
return <info type="INFORMATION">False</info>

View File

@@ -13,8 +13,8 @@ PyFile:BlockWithoutColon.py
PyWhilePart
PsiElement(Py:WHILE_KEYWORD)('while')
PsiWhiteSpace(' ')
PyBoolLiteralExpression
PsiElement(Py:TRUE_KEYWORD)('True')
PyReferenceExpression: True
PsiElement(Py:IDENTIFIER)('True')
PsiErrorElement:Colon expected
<empty list>
PsiWhiteSpace('\n ')

View File

@@ -12,8 +12,8 @@ PyFile:ErrorInParameterList.py
PyNamedParameter('filds')
PsiElement(Py:IDENTIFIER)('filds')
PsiElement(Py:EQ)('=')
PyNoneLiteralExpression
PsiElement(Py:NONE_KEYWORD)('None')
PyReferenceExpression: None
PsiElement(Py:IDENTIFIER)('None')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PsiErrorElement:formal parameter name expected

View File

@@ -19,8 +19,8 @@ PyFile:LambdaComprehension.py
<empty list>
PsiElement(Py:COLON)(':')
PsiWhiteSpace(' ')
PyBoolLiteralExpression
PsiElement(Py:TRUE_KEYWORD)('True')
PyReferenceExpression: True
PsiElement(Py:IDENTIFIER)('True')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PyLambdaExpression
@@ -29,8 +29,8 @@ PyFile:LambdaComprehension.py
<empty list>
PsiElement(Py:COLON)(':')
PsiWhiteSpace(' ')
PyBoolLiteralExpression
PsiElement(Py:FALSE_KEYWORD)('False')
PyReferenceExpression: False
PsiElement(Py:IDENTIFIER)('False')
PsiWhiteSpace(' ')
PsiElement(Py:IF_KEYWORD)('if')
PsiWhiteSpace(' ')

View File

@@ -14,8 +14,8 @@ PyFile:NotClosedSlice.py
PyIfPartIf
PsiElement(Py:IF_KEYWORD)('if')
PsiWhiteSpace(' ')
PyBoolLiteralExpression
PsiElement(Py:TRUE_KEYWORD)('True')
PyReferenceExpression: True
PsiElement(Py:IDENTIFIER)('True')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList

View File

@@ -3,8 +3,8 @@ PyFile:ResetAfterSemicolon.py
PyIfPartIf
PsiElement(Py:IF_KEYWORD)('if')
PsiWhiteSpace(' ')
PyBoolLiteralExpression
PsiElement(Py:TRUE_KEYWORD)('True')
PyReferenceExpression: True
PsiElement(Py:IDENTIFIER)('True')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList