From 192ca70649a278e8593bff91151956bc7649ac07 Mon Sep 17 00:00:00 2001
From: Erik Verbruggen <erik.verbruggen@nokia.com>
Date: Wed, 6 Oct 2010 16:26:48 +0200
Subject: [PATCH] C++ Parser: fix infinite loop when recovering from incorrect
 @selector expression.

---
 src/shared/cplusplus/Parser.cpp      | 12 ++++++--
 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 eb1b7f74637..414b27fbbd4 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 af819e871f9..bc10347f54c 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"
-- 
GitLab