mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-14 09:12:22 +07:00
improve parser recovery if keyword is used as function or class name (PY-8319)
This commit is contained in:
@@ -44,12 +44,7 @@ public class FunctionParsing extends Parsing {
|
||||
|
||||
protected void parseFunctionInnards(PsiBuilder.Marker functionMarker) {
|
||||
myBuilder.advanceLexer();
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.IDENTIFIER) {
|
||||
myBuilder.advanceLexer();
|
||||
}
|
||||
else {
|
||||
myBuilder.error(message("PARSE.expected.func.name"));
|
||||
}
|
||||
checkMatchesOrSkip(PyTokenTypes.IDENTIFIER, message("PARSE.expected.func.name"));
|
||||
parseParameterList();
|
||||
parseReturnTypeAnnotation();
|
||||
checkMatches(PyTokenTypes.COLON, message("PARSE.expected.colon"));
|
||||
|
||||
@@ -61,6 +61,17 @@ public class Parsing {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean checkMatchesOrSkip(final IElementType token, final String message) {
|
||||
if (myBuilder.getTokenType() == token) {
|
||||
myBuilder.advanceLexer();
|
||||
return true;
|
||||
}
|
||||
PsiBuilder.Marker mark = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
mark.error(message);
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void assertCurrentToken(final PyElementType tokenType) {
|
||||
LOG.assertTrue(myBuilder.getTokenType() == tokenType);
|
||||
}
|
||||
|
||||
@@ -777,7 +777,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
public void parseClassDeclaration(PsiBuilder.Marker classMarker, ParsingScope scope) {
|
||||
assertCurrentToken(PyTokenTypes.CLASS_KEYWORD);
|
||||
myBuilder.advanceLexer();
|
||||
checkMatches(PyTokenTypes.IDENTIFIER, IDENTIFIER_EXPECTED);
|
||||
checkMatchesOrSkip(PyTokenTypes.IDENTIFIER, IDENTIFIER_EXPECTED);
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.LPAR) {
|
||||
getExpressionParser().parseArgumentList();
|
||||
}
|
||||
|
||||
2
python/testData/psi/KeywordAsClassName.py
Normal file
2
python/testData/psi/KeywordAsClassName.py
Normal file
@@ -0,0 +1,2 @@
|
||||
class from:
|
||||
pass
|
||||
13
python/testData/psi/KeywordAsClassName.txt
Normal file
13
python/testData/psi/KeywordAsClassName.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
PyFile:KeywordAsClassName.py
|
||||
PyClass: null
|
||||
PsiElement(Py:CLASS_KEYWORD)('class')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiErrorElement:Identifier expected
|
||||
PsiElement(Py:FROM_KEYWORD)('from')
|
||||
PyArgumentList
|
||||
<empty list>
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyPassStatement
|
||||
PsiElement(Py:PASS_KEYWORD)('pass')
|
||||
2
python/testData/psi/KeywordAsFunctionName.py
Normal file
2
python/testData/psi/KeywordAsFunctionName.py
Normal file
@@ -0,0 +1,2 @@
|
||||
def from():
|
||||
pass
|
||||
14
python/testData/psi/KeywordAsFunctionName.txt
Normal file
14
python/testData/psi/KeywordAsFunctionName.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
PyFile:KeywordAsFunctionName.py
|
||||
PyFunction('null')
|
||||
PsiElement(Py:DEF_KEYWORD)('def')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiErrorElement:function name expected
|
||||
PsiElement(Py:FROM_KEYWORD)('from')
|
||||
PyParameterList
|
||||
PsiElement(Py:LPAR)('(')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyPassStatement
|
||||
PsiElement(Py:PASS_KEYWORD)('pass')
|
||||
@@ -410,6 +410,14 @@ public class PythonParsingTest extends ParsingTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testKeywordAsClassName() { // PY-8319
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testKeywordAsFunctionName() { // PY-8319
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void doTest(LanguageLevel languageLevel) {
|
||||
LanguageLevel prev = myLanguageLevel;
|
||||
myLanguageLevel = languageLevel;
|
||||
|
||||
Reference in New Issue
Block a user