forked from qt-creator/qt-creator
C++ Parser: fix infinite loop when recovering from incorrect @selector expression.
This commit is contained in:
@@ -4041,12 +4041,12 @@ bool Parser::parseObjCSelectorExpression(ExpressionAST *&node)
|
||||
last->value->name_token = identifier_token;
|
||||
last->value->colon_token = consumeToken();
|
||||
|
||||
while (LA() != T_RPAREN) {
|
||||
while (LA(1) == T_IDENTIFIER && LA(2) == T_COLON) {
|
||||
last->next = new (_pool) ObjCSelectorArgumentListAST;
|
||||
last = last->next;
|
||||
last->value = new (_pool) ObjCSelectorArgumentAST;
|
||||
match(T_IDENTIFIER, &last->value->name_token);
|
||||
match(T_COLON, &last->value->colon_token);
|
||||
last->value->name_token = consumeToken();
|
||||
last->value->colon_token = consumeToken();
|
||||
}
|
||||
} else {
|
||||
ObjCSelectorAST *args = new (_pool) ObjCSelectorAST;
|
||||
@@ -4056,7 +4056,13 @@ bool Parser::parseObjCSelectorExpression(ExpressionAST *&node)
|
||||
args->selector_argument_list->value->name_token = identifier_token;
|
||||
}
|
||||
|
||||
if (LA(1) == T_IDENTIFIER && LA(2) == T_RPAREN) {
|
||||
const char *txt = tok(1).spell();
|
||||
consumeToken();
|
||||
error(cursor(), "missing ':' after '%s'", txt);
|
||||
}
|
||||
match(T_RPAREN, &ast->rparen_token);
|
||||
|
||||
node = ast;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,8 @@ private slots:
|
||||
void objc_protocol_forward_declaration_1();
|
||||
void objc_protocol_definition_1();
|
||||
void objc_method_attributes_1();
|
||||
void objc_selector_error_recovery_1();
|
||||
void objc_selector_error_recovery_2();
|
||||
|
||||
// expressions with (square) brackets
|
||||
void normal_array_access();
|
||||
@@ -832,6 +834,45 @@ void tst_AST::objc_method_attributes_1()
|
||||
QCOMPARE(unit->spell(unavailableAttr->identifier_token), "unavailable");
|
||||
}
|
||||
|
||||
/*
|
||||
@selector(foo)
|
||||
@selector(foo:)
|
||||
@selector(foo:bar:)
|
||||
...
|
||||
*/
|
||||
void tst_AST::objc_selector_error_recovery_1()
|
||||
{
|
||||
QSharedPointer<TranslationUnit> unit(parseDeclaration("\n"
|
||||
"void tst() {\n"
|
||||
" @selector(foo:\n"
|
||||
" int i = 1;\n"
|
||||
"}\n"
|
||||
));
|
||||
AST *ast = unit->ast();
|
||||
QVERIFY(ast);
|
||||
ObjCClassDeclarationAST *zoo = ast->asObjCClassDeclaration();
|
||||
QVERIFY(zoo);
|
||||
QVERIFY(zoo->interface_token); QVERIFY(! (zoo->implementation_token));
|
||||
QVERIFY(zoo->class_name); QVERIFY(zoo->class_name->asSimpleName());
|
||||
QCOMPARE(unit->spell(zoo->class_name->asSimpleName()->identifier_token), "Zoo");
|
||||
}
|
||||
|
||||
void tst_AST::objc_selector_error_recovery_2()
|
||||
{
|
||||
QSharedPointer<TranslationUnit> unit(parseDeclaration("\n"
|
||||
"void tst() {\n"
|
||||
" @selector(foo:bar);\n"
|
||||
"}\n"
|
||||
));
|
||||
AST *ast = unit->ast();
|
||||
QVERIFY(ast);
|
||||
ObjCClassDeclarationAST *zoo = ast->asObjCClassDeclaration();
|
||||
QVERIFY(zoo);
|
||||
QVERIFY(zoo->interface_token); QVERIFY(! (zoo->implementation_token));
|
||||
QVERIFY(zoo->class_name); QVERIFY(zoo->class_name->asSimpleName());
|
||||
QCOMPARE(unit->spell(zoo->class_name->asSimpleName()->identifier_token), "Zoo");
|
||||
}
|
||||
|
||||
void tst_AST::normal_array_access()
|
||||
{
|
||||
QSharedPointer<TranslationUnit> unit(parseDeclaration("\n"
|
||||
|
||||
Reference in New Issue
Block a user