From 3cdd48067c8c865d050a19766948d05c86ec6e40 Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Fri, 3 Jul 2009 09:11:52 +0200
Subject: [PATCH] Introduced ForeachStatementAST and the bits to parse foreach
 statements when qtMocRun is enabled.

---
 src/libs/cplusplus/pp-engine.cpp          |  2 +
 src/shared/cplusplus/AST.cpp              | 18 +++++++++
 src/shared/cplusplus/AST.h                | 32 ++++++++++++++++
 src/shared/cplusplus/ASTClone.cpp         | 17 +++++++++
 src/shared/cplusplus/ASTVisit.cpp         | 15 ++++++++
 src/shared/cplusplus/ASTVisitor.h         |  2 +
 src/shared/cplusplus/ASTfwd.h             |  1 +
 src/shared/cplusplus/CheckDeclaration.cpp |  2 +-
 src/shared/cplusplus/CheckStatement.cpp   | 29 ++++++++++++++
 src/shared/cplusplus/CheckStatement.h     |  1 +
 src/shared/cplusplus/Control.h            |  2 +-
 src/shared/cplusplus/Keywords.cpp         | 22 +++++++++--
 src/shared/cplusplus/Parser.cpp           | 46 +++++++++++++++++++++--
 src/shared/cplusplus/Parser.h             |  1 +
 src/shared/cplusplus/Semantic.cpp         |  2 +-
 src/shared/cplusplus/Token.h              |  7 ++--
 16 files changed, 185 insertions(+), 14 deletions(-)

diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp
index 372926f5975..c614daf45eb 100644
--- a/src/libs/cplusplus/pp-engine.cpp
+++ b/src/libs/cplusplus/pp-engine.cpp
@@ -1421,6 +1421,8 @@ bool Preprocessor::isQtReservedWord(const QByteArray &macroId) const
     const int size = macroId.size();
     if      (size == 9 && macroId.at(0) == 'Q' && macroId == "Q_SIGNALS")
         return true;
+    else if (size == 9 && macroId.at(0) == 'Q' && macroId == "Q_FOREACH")
+        return true;
     else if (size == 7 && macroId.at(0) == 'Q' && macroId == "Q_SLOTS")
         return true;
     else if (size == 8 && macroId.at(0) == 'Q' && macroId == "Q_SIGNAL")
diff --git a/src/shared/cplusplus/AST.cpp b/src/shared/cplusplus/AST.cpp
index c809f6e1d02..dc6a5056775 100644
--- a/src/shared/cplusplus/AST.cpp
+++ b/src/shared/cplusplus/AST.cpp
@@ -874,6 +874,24 @@ unsigned ExpressionStatementAST::lastToken() const
     return 0;
 }
 
+unsigned ForeachStatementAST::firstToken() const
+{
+    return foreach_token;
+}
+
+unsigned ForeachStatementAST::lastToken() const
+{
+    if (statement)
+        return statement->lastToken();
+    else if (rparen_token)
+        return rparen_token + 1;
+    else if (expression)
+        return expression->lastToken();
+    else if (comma_token)
+        return comma_token + 1;
+
+    return foreach_token + 1;
+}
 
 unsigned ForStatementAST::firstToken() const
 {
diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h
index f345fd76b0c..d22735eeb14 100644
--- a/src/shared/cplusplus/AST.h
+++ b/src/shared/cplusplus/AST.h
@@ -131,6 +131,7 @@ public:
     virtual ExpressionListAST *asExpressionList() { return 0; }
     virtual ExpressionOrDeclarationStatementAST *asExpressionOrDeclarationStatement() { return 0; }
     virtual ExpressionStatementAST *asExpressionStatement() { return 0; }
+    virtual ForeachStatementAST *asForeachStatement() { return 0; }
     virtual ForStatementAST *asForStatement() { return 0; }
     virtual FunctionDeclaratorAST *asFunctionDeclarator() { return 0; }
     virtual FunctionDefinitionAST *asFunctionDefinition() { return 0; }
@@ -1135,6 +1136,37 @@ protected:
     virtual void accept0(ASTVisitor *visitor);
 };
 
+class CPLUSPLUS_EXPORT ForeachStatementAST: public StatementAST
+{
+public:
+    unsigned foreach_token;
+    unsigned lparen_token;
+    // declaration
+    SpecifierAST *type_specifiers;
+    DeclaratorAST *declarator;
+    // or an expression
+    ExpressionAST *initializer;
+    unsigned comma_token;
+    ExpressionAST *expression;
+    unsigned rparen_token;
+    StatementAST *statement;
+
+public: // annotations
+    Block *symbol;
+
+public:
+    virtual ForeachStatementAST *asForeachStatement()
+    { return this; }
+
+    virtual unsigned firstToken() const;
+    virtual unsigned lastToken() const;
+
+    virtual ForeachStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+    virtual void accept0(ASTVisitor *visitor);
+};
+
 class CPLUSPLUS_EXPORT ForStatementAST: public StatementAST
 {
 public:
diff --git a/src/shared/cplusplus/ASTClone.cpp b/src/shared/cplusplus/ASTClone.cpp
index c3eb1ab40fa..2e446c89ef1 100644
--- a/src/shared/cplusplus/ASTClone.cpp
+++ b/src/shared/cplusplus/ASTClone.cpp
@@ -514,6 +514,23 @@ FunctionDefinitionAST *FunctionDefinitionAST::clone(MemoryPool *pool) const
     return ast;
 }
 
+ForeachStatementAST *ForeachStatementAST::clone(MemoryPool *pool) const
+{
+    ForeachStatementAST *ast = new (pool) ForeachStatementAST;
+    // copy StatementAST
+    // copy ForeachStatementAST
+    ast->foreach_token = foreach_token;
+    ast->lparen_token = lparen_token;
+    if (type_specifiers) ast->type_specifiers = type_specifiers->clone(pool);
+    if (declarator) ast->declarator = declarator->clone(pool);
+    if (initializer) ast->initializer = initializer->clone(pool);
+    ast->comma_token = comma_token;
+    if (expression) ast->expression = expression->clone(pool);
+    ast->rparen_token = rparen_token;
+    if (statement) ast->statement = statement->clone(pool);
+    return ast;
+}
+
 ForStatementAST *ForStatementAST::clone(MemoryPool *pool) const
 {
     ForStatementAST *ast = new (pool) ForStatementAST;
diff --git a/src/shared/cplusplus/ASTVisit.cpp b/src/shared/cplusplus/ASTVisit.cpp
index c85ce397078..1673577474f 100644
--- a/src/shared/cplusplus/ASTVisit.cpp
+++ b/src/shared/cplusplus/ASTVisit.cpp
@@ -474,6 +474,21 @@ void FunctionDefinitionAST::accept0(ASTVisitor *visitor)
     visitor->endVisit(this);
 }
 
+void ForeachStatementAST::accept0(ASTVisitor *visitor)
+{
+    if (visitor->visit(this)) {
+        // visit ForeachStatementAST
+        for (SpecifierAST *it = type_specifiers; it; it = it->next)
+            accept(it, visitor);
+        accept(declarator, visitor);
+        accept(initializer, visitor);
+        accept(expression, visitor);
+        accept(statement, visitor);
+        // visit StatementAST
+    }
+    visitor->endVisit(this);
+}
+
 void ForStatementAST::accept0(ASTVisitor *visitor)
 {
     if (visitor->visit(this)) {
diff --git a/src/shared/cplusplus/ASTVisitor.h b/src/shared/cplusplus/ASTVisitor.h
index 45c8d89efc7..caa93e5e1b8 100644
--- a/src/shared/cplusplus/ASTVisitor.h
+++ b/src/shared/cplusplus/ASTVisitor.h
@@ -134,6 +134,7 @@ public:
     virtual bool visit(ExpressionListAST *) { return true; }
     virtual bool visit(ExpressionOrDeclarationStatementAST *) { return true; }
     virtual bool visit(ExpressionStatementAST *) { return true; }
+    virtual bool visit(ForeachStatementAST *) { return true; }
     virtual bool visit(ForStatementAST *) { return true; }
     virtual bool visit(FunctionDeclaratorAST *) { return true; }
     virtual bool visit(FunctionDefinitionAST *) { return true; }
@@ -242,6 +243,7 @@ public:
     virtual void endVisit(ExpressionListAST *) { }
     virtual void endVisit(ExpressionOrDeclarationStatementAST *) { }
     virtual void endVisit(ExpressionStatementAST *) { }
+    virtual void endVisit(ForeachStatementAST *) { }
     virtual void endVisit(ForStatementAST *) { }
     virtual void endVisit(FunctionDeclaratorAST *) { }
     virtual void endVisit(FunctionDefinitionAST *) { }
diff --git a/src/shared/cplusplus/ASTfwd.h b/src/shared/cplusplus/ASTfwd.h
index 0f4d9581bfb..ee5f8e876ff 100644
--- a/src/shared/cplusplus/ASTfwd.h
+++ b/src/shared/cplusplus/ASTfwd.h
@@ -101,6 +101,7 @@ class ExpressionAST;
 class ExpressionListAST;
 class ExpressionOrDeclarationStatementAST;
 class ExpressionStatementAST;
+class ForeachStatementAST;
 class ForStatementAST;
 class FunctionDeclaratorAST;
 class FunctionDefinitionAST;
diff --git a/src/shared/cplusplus/CheckDeclaration.cpp b/src/shared/cplusplus/CheckDeclaration.cpp
index 038d70b9a48..1bd8086cdbc 100644
--- a/src/shared/cplusplus/CheckDeclaration.cpp
+++ b/src/shared/cplusplus/CheckDeclaration.cpp
@@ -251,7 +251,7 @@ bool CheckDeclaration::visit(AccessDeclarationAST *ast)
     semantic()->switchVisibility(visibility);
     if (ast->slots_token)
         semantic()->switchMethodKey(Function::SlotMethod);
-    else if (accessSpecifier == T_SIGNALS)
+    else if (accessSpecifier == T_Q_SIGNALS)
         semantic()->switchMethodKey(Function::SignalMethod);
     else
         semantic()->switchMethodKey(Function::NormalMethod);
diff --git a/src/shared/cplusplus/CheckStatement.cpp b/src/shared/cplusplus/CheckStatement.cpp
index 0d7bced86ec..c93eca0492d 100644
--- a/src/shared/cplusplus/CheckStatement.cpp
+++ b/src/shared/cplusplus/CheckStatement.cpp
@@ -141,6 +141,35 @@ bool CheckStatement::visit(ExpressionStatementAST *ast)
     return false;
 }
 
+bool CheckStatement::visit(ForeachStatementAST *ast)
+{
+    Block *block = control()->newBlock(ast->foreach_token);
+    block->setStartOffset(tokenAt(ast->firstToken()).offset);
+    block->setEndOffset(tokenAt(ast->lastToken()).offset);
+    ast->symbol = block;
+    _scope->enterSymbol(block);
+    Scope *previousScope = switchScope(block->members());
+    if (ast->type_specifiers && ast->declarator) {
+        FullySpecifiedType ty = semantic()->check(ast->type_specifiers, _scope);
+        Name *name = 0;
+        ty = semantic()->check(ast->declarator, ty, _scope, &name);
+        unsigned location = ast->declarator->firstToken();
+        if (CoreDeclaratorAST *core_declarator = ast->declarator->core_declarator)
+            location = core_declarator->firstToken();
+        Declaration *decl = control()->newDeclaration(location, name);
+        decl->setType(ty);
+        _scope->enterSymbol(decl);
+    } else {
+        FullySpecifiedType exprTy = semantic()->check(ast->initializer, _scope);
+        (void) exprTy;
+    }
+
+    FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+    semantic()->check(ast->statement, _scope);
+    (void) switchScope(previousScope);
+    return false;
+}
+
 bool CheckStatement::visit(ForStatementAST *ast)
 {
     Block *block = control()->newBlock(ast->for_token);
diff --git a/src/shared/cplusplus/CheckStatement.h b/src/shared/cplusplus/CheckStatement.h
index 59b74b13635..baa2bdccf39 100644
--- a/src/shared/cplusplus/CheckStatement.h
+++ b/src/shared/cplusplus/CheckStatement.h
@@ -75,6 +75,7 @@ protected:
     virtual bool visit(DoStatementAST *ast);
     virtual bool visit(ExpressionOrDeclarationStatementAST *ast);
     virtual bool visit(ExpressionStatementAST *ast);
+    virtual bool visit(ForeachStatementAST *ast);
     virtual bool visit(ForStatementAST *ast);
     virtual bool visit(IfStatementAST *ast);
     virtual bool visit(LabeledStatementAST *ast);
diff --git a/src/shared/cplusplus/Control.h b/src/shared/cplusplus/Control.h
index b06063d4f52..8b4f09afffb 100644
--- a/src/shared/cplusplus/Control.h
+++ b/src/shared/cplusplus/Control.h
@@ -115,7 +115,7 @@ public:
     NamedType *namedType(Name *name);
 
     /// Creates a new Declaration symbol.
-    Declaration *newDeclaration(unsigned sourceLocation, Name *name = 0);
+    Declaration *newDeclaration(unsigned sourceLocation, Name *name);
 
     /// Creates a new Argument symbol.
     Argument *newArgument(unsigned sourceLocation, Name *name = 0);
diff --git a/src/shared/cplusplus/Keywords.cpp b/src/shared/cplusplus/Keywords.cpp
index e1b605668a0..e26244a0af7 100644
--- a/src/shared/cplusplus/Keywords.cpp
+++ b/src/shared/cplusplus/Keywords.cpp
@@ -297,7 +297,7 @@ static inline int classify5(const char *s, bool q) {
         if (s[2] == 'o') {
           if (s[3] == 't') {
             if (s[4] == 's') {
-              return T_SLOTS;
+              return T_Q_SLOTS;
             }
           }
         }
@@ -627,7 +627,7 @@ static inline int classify7(const char *s, bool q) {
           if (s[4] == 'a') {
             if (s[5] == 'l') {
               if (s[6] == 's') {
-                return T_SIGNALS;
+                return T_Q_SIGNALS;
               }
             }
           }
@@ -687,7 +687,7 @@ static inline int classify7(const char *s, bool q) {
           if (s[4] == 'O') {
             if (s[5] == 'T') {
               if (s[6] == 'S') {
-                return T_SLOTS;
+                return T_Q_SLOTS;
               }
             }
           }
@@ -950,7 +950,21 @@ static inline int classify9(const char *s, bool q) {
               if (s[6] == 'A') {
                 if (s[7] == 'L') {
                   if (s[8] == 'S') {
-                    return T_SIGNALS;
+                    return T_Q_SIGNALS;
+                  }
+                }
+              }
+            }
+          }
+        }
+      } else if (s[2] == 'F') {
+        if (s[3] == 'O') {
+          if (s[4] == 'R') {
+            if (s[5] == 'E') {
+              if (s[6] == 'A') {
+                if (s[7] == 'C') {
+                  if (s[8] == 'H') {
+                    return T_Q_FOREACH;
                   }
                 }
               }
diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp
index 08266e9f79d..dba11df7130 100644
--- a/src/shared/cplusplus/Parser.cpp
+++ b/src/shared/cplusplus/Parser.cpp
@@ -1464,11 +1464,11 @@ bool Parser::parseAccessSpecifier(SpecifierAST *&node)
 
 bool Parser::parseAccessDeclaration(DeclarationAST *&node)
 {
-    if (LA() == T_PUBLIC || LA() == T_PROTECTED || LA() == T_PRIVATE || LA() == T_SIGNALS) {
-        bool isSignals = LA() == T_SIGNALS;
+    if (LA() == T_PUBLIC || LA() == T_PROTECTED || LA() == T_PRIVATE || LA() == T_Q_SIGNALS) {
+        bool isSignals = LA() == T_Q_SIGNALS;
         AccessDeclarationAST *ast = new (_pool) AccessDeclarationAST;
         ast->access_specifier_token = consumeToken();
-        if (! isSignals && LA() == T_SLOTS)
+        if (! isSignals && LA() == T_Q_SLOTS)
             ast->slots_token = consumeToken();
         match(T_COLON, &ast->colon_token);
         node = ast;
@@ -1489,7 +1489,7 @@ bool Parser::parseMemberSpecification(DeclarationAST *&node)
     case T_TEMPLATE:
         return parseTemplateDeclaration(node);
 
-    case T_SIGNALS:
+    case T_Q_SIGNALS:
     case T_PUBLIC:
     case T_PROTECTED:
     case T_PRIVATE:
@@ -1861,6 +1861,9 @@ bool Parser::parseStatement(StatementAST *&node)
     case T_DO:
         return parseDoStatement(node);
 
+    case T_Q_FOREACH:
+        return parseForeachStatement(node);
+
     case T_FOR:
         return parseForStatement(node);
 
@@ -2108,6 +2111,41 @@ bool Parser::parseDoStatement(StatementAST *&node)
     return false;
 }
 
+bool Parser::parseForeachStatement(StatementAST *&node)
+{
+    if (LA() == T_Q_FOREACH) {
+        ForeachStatementAST *ast = new (_pool) ForeachStatementAST;
+        ast->foreach_token = consumeToken();
+        match(T_LPAREN, &ast->lparen_token);
+
+        unsigned startOfTypeSpecifier = cursor();
+        bool blocked = blockErrors(true);
+
+        if (parseTypeSpecifier(ast->type_specifiers))
+            parseDeclarator(ast->declarator);
+
+        if (! ast->type_specifiers || ! ast->declarator) {
+            ast->type_specifiers = 0;
+            ast->declarator = 0;
+
+            blockErrors(blocked);
+            rewind(startOfTypeSpecifier);
+            parseExpression(ast->expression);
+        }
+
+        blockErrors(blocked);
+
+        match(T_COMMA, &ast->comma_token);
+        parseExpression(ast->expression);
+        match(T_RPAREN, &ast->rparen_token);
+        parseStatement(ast->statement);
+
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
 bool Parser::parseForStatement(StatementAST *&node)
 {
     if (LA() == T_FOR) {
diff --git a/src/shared/cplusplus/Parser.h b/src/shared/cplusplus/Parser.h
index 330bb84b3d7..c5515b05ec0 100644
--- a/src/shared/cplusplus/Parser.h
+++ b/src/shared/cplusplus/Parser.h
@@ -121,6 +121,7 @@ public:
     bool parseExpressionOrDeclarationStatement(StatementAST *&node);
     bool parseExpressionStatement(StatementAST *&node);
     bool parseForInitStatement(StatementAST *&node);
+    bool parseForeachStatement(StatementAST *&node);
     bool parseForStatement(StatementAST *&node);
     bool parseFunctionBody(StatementAST *&node);
     bool parseIfStatement(StatementAST *&node);
diff --git a/src/shared/cplusplus/Semantic.cpp b/src/shared/cplusplus/Semantic.cpp
index 9e7108bbc54..6f44072302e 100644
--- a/src/shared/cplusplus/Semantic.cpp
+++ b/src/shared/cplusplus/Semantic.cpp
@@ -179,7 +179,7 @@ int Semantic::visibilityForAccessSpecifier(int tokenKind) const
         return Symbol::Protected;
     case T_PRIVATE:
         return Symbol::Private;
-    case T_SIGNALS:
+    case T_Q_SIGNALS:
         return Symbol::Protected;
     default:
         return Symbol::Public;
diff --git a/src/shared/cplusplus/Token.h b/src/shared/cplusplus/Token.h
index 660e91e4b67..6774dba3361 100644
--- a/src/shared/cplusplus/Token.h
+++ b/src/shared/cplusplus/Token.h
@@ -234,10 +234,11 @@ enum Kind {
     T_SLOT,
     T_Q_SIGNAL,
     T_Q_SLOT,
-    T_SIGNALS,
-    T_SLOTS,
+    T_Q_SIGNALS,
+    T_Q_SLOTS,
+    T_Q_FOREACH,
 
-    T_LAST_KEYWORD = T_SLOTS,
+    T_LAST_KEYWORD = T_Q_FOREACH,
 
     // aliases
     T_OR = T_PIPE_PIPE,
-- 
GitLab