From 16542241c91d6a4296bfbd18077de4eff1f43c8b Mon Sep 17 00:00:00 2001
From: Christian Kamm <christian.d.kamm@nokia.com>
Date: Wed, 8 Dec 2010 15:08:03 +0100
Subject: [PATCH] C++: Add parsing of Q_PRIVATE_PROPERTY.

Reviewed-by: Roberto Raggi
---
 src/libs/cplusplus/pp-engine.cpp          |  2 ++
 src/plugins/cpptools/cppcodeformatter.cpp |  1 +
 src/shared/cplusplus/AST.cpp              | 10 ++++++
 src/shared/cplusplus/AST.h                |  4 +++
 src/shared/cplusplus/ASTClone.cpp         |  3 ++
 src/shared/cplusplus/ASTMatcher.cpp       |  7 ++++
 src/shared/cplusplus/ASTVisit.cpp         |  1 +
 src/shared/cplusplus/Keywords.cpp         | 42 +++++++++++++++++++++++
 src/shared/cplusplus/Parser.cpp           | 17 ++++++++-
 src/shared/cplusplus/Token.h              |  1 +
 tests/tools/cplusplus-dump/dumpers.inc    |  3 ++
 11 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp
index 15a7151a1e6..763ed6ff1c6 100644
--- a/src/libs/cplusplus/pp-engine.cpp
+++ b/src/libs/cplusplus/pp-engine.cpp
@@ -1432,6 +1432,8 @@ bool Preprocessor::isQtReservedWord(const QByteArray &macroId) const
         return true;
     else if (size == 10 && macroId.at(0) == 'Q' && macroId == "Q_PROPERTY")
         return true;
+    else if (size == 18 && macroId.at(0) == 'Q' && macroId == "Q_PRIVATE_PROPERTY")
+        return true;
     else if (size == 7 && macroId.at(0) == 'Q' && macroId == "Q_ENUMS")
         return true;
     else if (size == 7 && macroId.at(0) == 'Q' && macroId == "Q_FLAGS")
diff --git a/src/plugins/cpptools/cppcodeformatter.cpp b/src/plugins/cpptools/cppcodeformatter.cpp
index fdb179f3a44..d46c6c7271c 100644
--- a/src/plugins/cpptools/cppcodeformatter.cpp
+++ b/src/plugins/cpptools/cppcodeformatter.cpp
@@ -702,6 +702,7 @@ bool CodeFormatter::tryDeclaration()
     switch (kind) {
     case T_Q_ENUMS:
     case T_Q_PROPERTY:
+    case T_Q_PRIVATE_PROPERTY:
     case T_Q_FLAGS:
     case T_Q_GADGET:
     case T_Q_OBJECT:
diff --git a/src/shared/cplusplus/AST.cpp b/src/shared/cplusplus/AST.cpp
index 1db8baadeed..0ef2b0e0620 100644
--- a/src/shared/cplusplus/AST.cpp
+++ b/src/shared/cplusplus/AST.cpp
@@ -3387,6 +3387,11 @@ unsigned QtPropertyDeclarationAST::firstToken() const
         return property_specifier_token;
     if (lparen_token)
         return lparen_token;
+    if (expression)
+        if (unsigned candidate = expression->firstToken())
+            return candidate;
+    if (comma_token)
+        return comma_token;
     if (type_id)
         if (unsigned candidate = type_id->firstToken())
             return candidate;
@@ -3415,6 +3420,11 @@ unsigned QtPropertyDeclarationAST::lastToken() const
     if (type_id)
         if (unsigned candidate = type_id->lastToken())
             return candidate;
+    if (comma_token)
+        return comma_token + 1;
+    if (expression)
+        if (unsigned candidate = expression->lastToken())
+            return candidate;
     if (lparen_token)
         return lparen_token + 1;
     if (property_specifier_token)
diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h
index cacf686da68..267ee29d970 100644
--- a/src/shared/cplusplus/AST.h
+++ b/src/shared/cplusplus/AST.h
@@ -773,6 +773,8 @@ class CPLUSPLUS_EXPORT QtPropertyDeclarationAST: public DeclarationAST
 public:
     unsigned property_specifier_token;
     unsigned lparen_token;
+    ExpressionAST *expression; // for Q_PRIVATE_PROPERTY(expression, ...)
+    unsigned comma_token;
     ExpressionAST *type_id;
     NameAST *property_name;
     QtPropertyDeclarationItemListAST *property_declaration_item_list;
@@ -782,6 +784,8 @@ public:
     QtPropertyDeclarationAST()
         : property_specifier_token(0)
         , lparen_token(0)
+        , expression(0)
+        , comma_token(0)
         , type_id(0)
         , property_name(0)
         , property_declaration_item_list(0)
diff --git a/src/shared/cplusplus/ASTClone.cpp b/src/shared/cplusplus/ASTClone.cpp
index 3a7ac4782ca..749f0ce7c30 100644
--- a/src/shared/cplusplus/ASTClone.cpp
+++ b/src/shared/cplusplus/ASTClone.cpp
@@ -198,6 +198,9 @@ QtPropertyDeclarationAST *QtPropertyDeclarationAST::clone(MemoryPool *pool) cons
     QtPropertyDeclarationAST *ast = new (pool) QtPropertyDeclarationAST;
     ast->property_specifier_token = property_specifier_token;
     ast->lparen_token = lparen_token;
+    if (expression)
+        ast->expression = expression->clone(pool);
+    ast->comma_token = comma_token;
     if (type_id)
         ast->type_id = type_id->clone(pool);
     if (property_name)
diff --git a/src/shared/cplusplus/ASTMatcher.cpp b/src/shared/cplusplus/ASTMatcher.cpp
index e14a79f3fbc..c853f6d4d1c 100644
--- a/src/shared/cplusplus/ASTMatcher.cpp
+++ b/src/shared/cplusplus/ASTMatcher.cpp
@@ -301,6 +301,13 @@ bool ASTMatcher::match(QtPropertyDeclarationAST *node, QtPropertyDeclarationAST
 
     pattern->lparen_token = node->lparen_token;
 
+    if (! pattern->expression)
+        pattern->expression = node->expression;
+    else if (! AST::match(node->expression, pattern->expression, this))
+        return false;
+
+    pattern->comma_token = node->comma_token;
+
     if (! pattern->type_id)
         pattern->type_id = node->type_id;
     else if (! AST::match(node->type_id, pattern->type_id, this))
diff --git a/src/shared/cplusplus/ASTVisit.cpp b/src/shared/cplusplus/ASTVisit.cpp
index 893339a2a83..16ce0fc572e 100644
--- a/src/shared/cplusplus/ASTVisit.cpp
+++ b/src/shared/cplusplus/ASTVisit.cpp
@@ -154,6 +154,7 @@ void QtPropertyDeclarationItemAST::accept0(ASTVisitor *visitor)
 void QtPropertyDeclarationAST::accept0(ASTVisitor *visitor)
 {
     if (visitor->visit(this)) {
+        accept(expression, visitor);
         accept(type_id, visitor);
         accept(property_name, visitor);
         accept(property_declaration_item_list, visitor);
diff --git a/src/shared/cplusplus/Keywords.cpp b/src/shared/cplusplus/Keywords.cpp
index 340f418547e..ed32aeb021c 100644
--- a/src/shared/cplusplus/Keywords.cpp
+++ b/src/shared/cplusplus/Keywords.cpp
@@ -1442,6 +1442,47 @@ static inline int classify14(const char *s, bool q, bool) {
   return T_IDENTIFIER;
 }
 
+static inline int classify18(const char *s, bool q, bool) {
+  if (q && s[0] == 'Q') {
+    if (s[1] == '_') {
+      if (s[2] == 'P') {
+        if (s[3] == 'R') {
+          if (s[4] == 'I') {
+            if (s[5] == 'V') {
+              if (s[6] == 'A') {
+                if (s[7] == 'T') {
+                  if (s[8] == 'E') {
+                    if (s[9] == '_') {
+                      if (s[10] == 'P') {
+                        if (s[11] == 'R') {
+                          if (s[12] == 'O') {
+                            if (s[13] == 'P') {
+                              if (s[14] == 'E') {
+                                if (s[15] == 'R') {
+                                  if (s[16] == 'T') {
+                                    if (s[17] == 'Y') {
+                                      return T_Q_PRIVATE_PROPERTY;
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  return T_IDENTIFIER;
+}
+
 static inline int classify19(const char *s, bool q, bool) {
   if (q && s[0] == 'Q') {
     if (s[1] == '_') {
@@ -1502,6 +1543,7 @@ int Lexer::classify(const char *s, int n, bool q, bool x) {
     case 13: return classify13(s, q, x);
     case 14: return classify14(s, q, x);
     case 16: return classify16(s, q, x);
+    case 18: return classify18(s, q, x);
     case 19: return classify19(s, q, x);
     default: return T_IDENTIFIER;
   } // switch
diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp
index 4bd4a196aaf..d7b3dad29f1 100644
--- a/src/shared/cplusplus/Parser.cpp
+++ b/src/shared/cplusplus/Parser.cpp
@@ -286,6 +286,7 @@ void Parser::skipUntilDeclaration()
         case T_Q_SIGNALS:
         case T_Q_SLOTS:
         case T_Q_PROPERTY:
+        case T_Q_PRIVATE_PROPERTY:
         case T_Q_ENUMS:
         case T_Q_FLAGS:
         case T_Q_INTERFACES:
@@ -1972,13 +1973,26 @@ bool Parser::parseAccessDeclaration(DeclarationAST *&node)
 bool Parser::parseQtPropertyDeclaration(DeclarationAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_Q_PROPERTY)
+    const bool privateProperty = (LA() == T_Q_PRIVATE_PROPERTY);
+    if (LA() != T_Q_PROPERTY && !privateProperty)
         return false;
 
     QtPropertyDeclarationAST *ast = new (_pool)QtPropertyDeclarationAST;
     ast->property_specifier_token = consumeToken();
     if (LA() == T_LPAREN) {
         ast->lparen_token = consumeToken();
+
+        if (privateProperty) {
+            if (parsePostfixExpression(ast->expression)) {
+                match(T_COMMA, &ast->comma_token);
+            } else {
+                error(cursor(),
+                      "expected expression before `%s'",
+                      tok().spell());
+                return true;
+            }
+        }
+
         parseTypeId(ast->type_id);
 
         SimpleNameAST *property_name = new (_pool) SimpleNameAST;
@@ -2238,6 +2252,7 @@ bool Parser::parseMemberSpecification(DeclarationAST *&node, ClassSpecifierAST *
         return parseAccessDeclaration(node);
 
     case T_Q_PROPERTY:
+    case T_Q_PRIVATE_PROPERTY:
         return parseQtPropertyDeclaration(node);
 
     case T_Q_ENUMS:
diff --git a/src/shared/cplusplus/Token.h b/src/shared/cplusplus/Token.h
index 49175692d78..bbc0149543b 100644
--- a/src/shared/cplusplus/Token.h
+++ b/src/shared/cplusplus/Token.h
@@ -244,6 +244,7 @@ enum Kind {
     T_Q_Q,
     T_Q_INVOKABLE,
     T_Q_PROPERTY,
+    T_Q_PRIVATE_PROPERTY,
     T_Q_INTERFACES,
     T_Q_ENUMS,
     T_Q_FLAGS,
diff --git a/tests/tools/cplusplus-dump/dumpers.inc b/tests/tools/cplusplus-dump/dumpers.inc
index ec49d7aced9..fdee4f1c1c1 100644
--- a/tests/tools/cplusplus-dump/dumpers.inc
+++ b/tests/tools/cplusplus-dump/dumpers.inc
@@ -198,6 +198,9 @@ virtual bool visit(QtPropertyDeclarationAST *ast)
         terminal(ast->property_specifier_token, ast);
     if (ast->lparen_token)
         terminal(ast->lparen_token, ast);
+    nonterminal(ast->expression);
+    if (ast->comma_token)
+        terminal(ast->comma_token, ast);
     nonterminal(ast->type_id);
     nonterminal(ast->property_name);
     for (QtPropertyDeclarationItemListAST *iter = ast->property_declaration_item_list; iter; iter = iter->next)
-- 
GitLab