diff options
-rw-r--r-- | src/shared/cplusplus/Parser.cpp | 12 | ||||
-rw-r--r-- | tests/auto/cplusplus/ast/tst_ast.cpp | 41 |
2 files changed, 50 insertions, 3 deletions
diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp index eb1b7f7463..414b27fbbd 100644 --- a/src/shared/cplusplus/Parser.cpp +++ b/src/shared/cplusplus/Parser.cpp @@ -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; } diff --git a/tests/auto/cplusplus/ast/tst_ast.cpp b/tests/auto/cplusplus/ast/tst_ast.cpp index af819e871f..bc10347f54 100644 --- a/tests/auto/cplusplus/ast/tst_ast.cpp +++ b/tests/auto/cplusplus/ast/tst_ast.cpp @@ -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" |