From b4d72a78dbe365a0b5578e453bb9daaeb0260996 Mon Sep 17 00:00:00 2001
From: Erik Verbruggen <erik.verbruggen@nokia.com>
Date: Tue, 16 Mar 2010 17:29:40 +0100
Subject: [PATCH] Added parser support for Q_INTERFACES.

---
 src/libs/cplusplus/pp-engine.cpp    |  2 +
 src/shared/cplusplus/AST.cpp        | 39 ++++++++++++++-
 src/shared/cplusplus/AST.h          | 42 ++++++++++++++++
 src/shared/cplusplus/ASTClone.cpp   | 23 +++++++++
 src/shared/cplusplus/ASTMatch0.cpp  | 16 ++++++
 src/shared/cplusplus/ASTMatcher.cpp | 37 ++++++++++++++
 src/shared/cplusplus/ASTMatcher.h   |  2 +
 src/shared/cplusplus/ASTVisit.cpp   | 17 +++++++
 src/shared/cplusplus/ASTVisitor.h   |  4 ++
 src/shared/cplusplus/ASTfwd.h       |  3 ++
 src/shared/cplusplus/Keywords.cpp   | 27 +++++++++-
 src/shared/cplusplus/Parser.cpp     | 76 +++++++++++++++++++++++++++++
 src/shared/cplusplus/Parser.h       |  1 +
 src/shared/cplusplus/Token.cpp      |  2 +-
 src/shared/cplusplus/Token.h        |  1 +
 15 files changed, 289 insertions(+), 3 deletions(-)

diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp
index 66d7f908e70..172f50fb4a3 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
         return true;
     else if (size == 7 && macroId.at(0) == 'Q' && macroId == "Q_FLAGS")
         return true;
+    else if (size == 12 && macroId.at(0) == 'Q' && macroId == "Q_INTERFACES")
+        return true;
     else if (size == 6 && macroId.at(0) == 'S' && macroId == "SIGNAL")
         return true;
     else if (size == 4 && macroId.at(0) == 'S' && macroId == "SLOT")
diff --git a/src/shared/cplusplus/AST.cpp b/src/shared/cplusplus/AST.cpp
index f6aebdb688f..6da6f08c65e 100644
--- a/src/shared/cplusplus/AST.cpp
+++ b/src/shared/cplusplus/AST.cpp
@@ -197,7 +197,7 @@ unsigned QtEnumDeclarationAST::lastToken() const
 
 unsigned QtFlagsDeclarationAST::firstToken() const
 {
-    return flags_specifier_token + 1;
+    return flags_specifier_token;
 }
 
 unsigned QtFlagsDeclarationAST::lastToken() const
@@ -212,6 +212,43 @@ unsigned QtFlagsDeclarationAST::lastToken() const
         return flags_specifier_token + 1;
 }
 
+unsigned QtInterfaceNameAST::firstToken() const
+{
+    if (interface_name)
+        return interface_name->firstToken();
+    else if (constraint_list)
+        return constraint_list->firstToken();
+    else
+        return 0;
+}
+
+unsigned QtInterfaceNameAST::lastToken() const
+{
+    if (constraint_list)
+        return constraint_list->lastToken();
+    else if (interface_name)
+        return interface_name->lastToken();
+    else
+        return 0;
+}
+
+unsigned QtInterfacesDeclarationAST::firstToken() const
+{
+    return interfaces_token;
+}
+
+unsigned QtInterfacesDeclarationAST::lastToken() const
+{
+    if (rparen_token)
+        return rparen_token + 1;
+    else if (interface_name_list)
+        return interface_name_list->lastToken();
+    else if (lparen_token)
+        return lparen_token + 1;
+    else
+        return interfaces_token + 1;
+}
+
 unsigned ArrayAccessAST::firstToken() const
 {
     return lbracket_token;
diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h
index 40147912bee..f9f13a0b7ad 100644
--- a/src/shared/cplusplus/AST.h
+++ b/src/shared/cplusplus/AST.h
@@ -256,6 +256,8 @@ public:
     virtual PtrOperatorAST *asPtrOperator() { return 0; }
     virtual QtEnumDeclarationAST *asQtEnumDeclaration() { return 0; }
     virtual QtFlagsDeclarationAST *asQtFlagsDeclaration() { return 0; }
+    virtual QtInterfaceNameAST *asQtInterfaceName() { return 0; }
+    virtual QtInterfacesDeclarationAST *asQtInterfacesDeclaration() { return 0; }
     virtual QtMemberDeclarationAST *asQtMemberDeclaration() { return 0; }
     virtual QtMethodAST *asQtMethod() { return 0; }
     virtual QtPropertyDeclarationAST *asQtPropertyDeclaration() { return 0; }
@@ -660,6 +662,46 @@ protected:
     virtual bool match0(AST *, ASTMatcher *);
 };
 
+class CPLUSPLUS_EXPORT QtInterfaceNameAST: public AST
+{
+public:
+    NameAST *interface_name;
+    NameListAST *constraint_list;
+
+public:
+    virtual QtInterfaceNameAST *asQtInterfaceName() { return this; }
+
+    virtual unsigned firstToken() const;
+    virtual unsigned lastToken() const;
+
+    virtual QtInterfaceNameAST *clone(MemoryPool *pool) const;
+
+protected:
+    virtual void accept0(ASTVisitor *visitor);
+    virtual bool match0(AST *, ASTMatcher *);
+};
+
+class CPLUSPLUS_EXPORT QtInterfacesDeclarationAST: public DeclarationAST
+{
+public:
+    unsigned interfaces_token;
+    unsigned lparen_token;
+    QtInterfaceNameListAST *interface_name_list;
+    unsigned rparen_token;
+
+public:
+    virtual QtInterfacesDeclarationAST *asQtInterfacesDeclaration() { return this; }
+
+    virtual unsigned firstToken() const;
+    virtual unsigned lastToken() const;
+
+    virtual QtInterfacesDeclarationAST *clone(MemoryPool *pool) const;
+
+protected:
+    virtual void accept0(ASTVisitor *visitor);
+    virtual bool match0(AST *, ASTMatcher *);
+};
+
 class CPLUSPLUS_EXPORT AsmDefinitionAST: public DeclarationAST
 {
 public:
diff --git a/src/shared/cplusplus/ASTClone.cpp b/src/shared/cplusplus/ASTClone.cpp
index f9d45b6fed7..1e58c3f692e 100644
--- a/src/shared/cplusplus/ASTClone.cpp
+++ b/src/shared/cplusplus/ASTClone.cpp
@@ -204,6 +204,29 @@ QtFlagsDeclarationAST *QtFlagsDeclarationAST::clone(MemoryPool *pool) const
     return ast;
 }
 
+QtInterfaceNameAST *QtInterfaceNameAST::clone(MemoryPool *pool) const
+{
+    QtInterfaceNameAST *ast = new (pool) QtInterfaceNameAST;
+    if (interface_name)
+        ast->interface_name = interface_name->clone(pool);
+    for (NameListAST *iter = constraint_list, **ast_iter = &ast->constraint_list;
+         iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
+        *ast_iter = new (pool) NameListAST((iter->value) ? iter->value->clone(pool) : 0);
+    return ast;
+}
+
+QtInterfacesDeclarationAST *QtInterfacesDeclarationAST::clone(MemoryPool *pool) const
+{
+    QtInterfacesDeclarationAST *ast = new (pool) QtInterfacesDeclarationAST;
+    ast->interfaces_token = interfaces_token;
+    ast->lparen_token = lparen_token;
+    for (QtInterfaceNameListAST *iter = interface_name_list, **ast_iter = &ast->interface_name_list;
+         iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
+        *ast_iter = new (pool) QtInterfaceNameListAST((iter->value) ? iter->value->clone(pool) : 0);
+    ast->rparen_token = rparen_token;
+    return ast;
+}
+
 AsmDefinitionAST *AsmDefinitionAST::clone(MemoryPool *pool) const
 {
     AsmDefinitionAST *ast = new (pool) AsmDefinitionAST;
diff --git a/src/shared/cplusplus/ASTMatch0.cpp b/src/shared/cplusplus/ASTMatch0.cpp
index 4347c7230b6..d594b441d2a 100644
--- a/src/shared/cplusplus/ASTMatch0.cpp
+++ b/src/shared/cplusplus/ASTMatch0.cpp
@@ -153,6 +153,22 @@ bool QtFlagsDeclarationAST::match0(AST *pattern, ASTMatcher *matcher)
     return false;
 }
 
+bool QtInterfaceNameAST::match0(AST *pattern, ASTMatcher *matcher)
+{
+    if (QtInterfaceNameAST *_other = pattern->asQtInterfaceName())
+        return matcher->match(this, _other);
+
+    return false;
+}
+
+bool QtInterfacesDeclarationAST::match0(AST *pattern, ASTMatcher *matcher)
+{
+    if (QtInterfacesDeclarationAST *_other = pattern->asQtInterfacesDeclaration())
+        return matcher->match(this, _other);
+
+    return false;
+}
+
 bool AsmDefinitionAST::match0(AST *pattern, ASTMatcher *matcher)
 {
     if (AsmDefinitionAST *_other = pattern->asAsmDefinition())
diff --git a/src/shared/cplusplus/ASTMatcher.cpp b/src/shared/cplusplus/ASTMatcher.cpp
index c9980d62e22..044f7b1f060 100644
--- a/src/shared/cplusplus/ASTMatcher.cpp
+++ b/src/shared/cplusplus/ASTMatcher.cpp
@@ -313,6 +313,43 @@ bool ASTMatcher::match(QtFlagsDeclarationAST *node, QtFlagsDeclarationAST *patte
     return true;
 }
 
+bool ASTMatcher::match(QtInterfaceNameAST *node, QtInterfaceNameAST *pattern)
+{
+    (void) node;
+    (void) pattern;
+
+    if (! pattern->interface_name)
+        pattern->interface_name = node->interface_name;
+    else if (! AST::match(node->interface_name, pattern->interface_name, this))
+        return false;
+
+    if (! pattern->constraint_list)
+        pattern->constraint_list = node->constraint_list;
+    else if (! AST::match(node->constraint_list, pattern->constraint_list, this))
+        return false;
+
+    return true;
+}
+
+bool ASTMatcher::match(QtInterfacesDeclarationAST *node, QtInterfacesDeclarationAST *pattern)
+{
+    (void) node;
+    (void) pattern;
+
+    pattern->interfaces_token = node->interfaces_token;
+
+    pattern->lparen_token = node->lparen_token;
+
+    if (! pattern->interface_name_list)
+        pattern->interface_name_list = node->interface_name_list;
+    else if (! AST::match(node->interface_name_list, pattern->interface_name_list, this))
+        return false;
+
+    pattern->rparen_token = node->rparen_token;
+
+    return true;
+}
+
 bool ASTMatcher::match(AsmDefinitionAST *node, AsmDefinitionAST *pattern)
 {
     (void) node;
diff --git a/src/shared/cplusplus/ASTMatcher.h b/src/shared/cplusplus/ASTMatcher.h
index 7dfeec7c16a..3de5b736a86 100644
--- a/src/shared/cplusplus/ASTMatcher.h
+++ b/src/shared/cplusplus/ASTMatcher.h
@@ -43,6 +43,8 @@ public:
     virtual bool match(QtPropertyDeclarationAST *node, QtPropertyDeclarationAST *pattern);
     virtual bool match(QtEnumDeclarationAST *node, QtEnumDeclarationAST *pattern);
     virtual bool match(QtFlagsDeclarationAST *node, QtFlagsDeclarationAST *pattern);
+    virtual bool match(QtInterfaceNameAST *node, QtInterfaceNameAST *pattern);
+    virtual bool match(QtInterfacesDeclarationAST *node, QtInterfacesDeclarationAST *pattern);
     virtual bool match(ArrayAccessAST *node, ArrayAccessAST *pattern);
     virtual bool match(ArrayDeclaratorAST *node, ArrayDeclaratorAST *pattern);
     virtual bool match(ArrayInitializerAST *node, ArrayInitializerAST *pattern);
diff --git a/src/shared/cplusplus/ASTVisit.cpp b/src/shared/cplusplus/ASTVisit.cpp
index df08727aec7..0e9575240d3 100644
--- a/src/shared/cplusplus/ASTVisit.cpp
+++ b/src/shared/cplusplus/ASTVisit.cpp
@@ -157,6 +157,23 @@ void QtFlagsDeclarationAST::accept0(ASTVisitor *visitor)
     visitor->endVisit(this);
 }
 
+void QtInterfaceNameAST::accept0(ASTVisitor *visitor)
+{
+    if (visitor->visit(this)) {
+        accept(interface_name, visitor);
+        accept(constraint_list, visitor);
+    }
+    visitor->endVisit(this);
+}
+
+void QtInterfacesDeclarationAST::accept0(ASTVisitor *visitor)
+{
+    if (visitor->visit(this)) {
+        accept(interface_name_list, visitor);
+    }
+    visitor->endVisit(this);
+}
+
 void AsmDefinitionAST::accept0(ASTVisitor *visitor)
 {
     if (visitor->visit(this)) {
diff --git a/src/shared/cplusplus/ASTVisitor.h b/src/shared/cplusplus/ASTVisitor.h
index bb1bea71092..25a9aa27419 100644
--- a/src/shared/cplusplus/ASTVisitor.h
+++ b/src/shared/cplusplus/ASTVisitor.h
@@ -204,6 +204,8 @@ public:
     virtual bool visit(QtMethodAST *) { return true; }
     virtual bool visit(QtMemberDeclarationAST *) { return true; }
     virtual bool visit(QtPropertyDeclarationItemAST *) { return true; }
+    virtual bool visit(QtInterfacesDeclarationAST *) { return true; }
+    virtual bool visit(QtInterfaceNameAST *) { return true; }
 
     // ObjC++
     virtual bool visit(ObjCClassDeclarationAST *) { return true; }
@@ -334,6 +336,8 @@ public:
     virtual void endVisit(QtMethodAST *) { }
     virtual void endVisit(QtMemberDeclarationAST *) { }
     virtual void endVisit(QtPropertyDeclarationItemAST *) { }
+    virtual void endVisit(QtInterfacesDeclarationAST *) { }
+    virtual void endVisit(QtInterfaceNameAST *) { }
 
     // ObjC++
     virtual void endVisit(ObjCClassDeclarationAST *) { }
diff --git a/src/shared/cplusplus/ASTfwd.h b/src/shared/cplusplus/ASTfwd.h
index 5779bdf0d34..d068f120362 100644
--- a/src/shared/cplusplus/ASTfwd.h
+++ b/src/shared/cplusplus/ASTfwd.h
@@ -163,6 +163,8 @@ class PostfixExpressionAST;
 class PtrOperatorAST;
 class QtEnumDeclarationAST;
 class QtFlagsDeclarationAST;
+class QtInterfaceNameAST;
+class QtInterfacesDeclarationAST;
 class QtMemberDeclarationAST;
 class QtMethodAST;
 class QtPropertyDeclarationAST;
@@ -213,6 +215,7 @@ typedef List<PtrOperatorAST *> PtrOperatorListAST;
 typedef List<SpecifierAST *> SpecifierListAST;
 typedef List<QtPropertyDeclarationItemAST *> QtPropertyDeclarationItemListAST;
 typedef List<NameAST *> NameListAST;
+typedef List<QtInterfaceNameAST *> QtInterfaceNameListAST;
 
 typedef List<ObjCMessageArgumentAST *> ObjCMessageArgumentListAST;
 typedef List<ObjCSelectorArgumentAST *> ObjCSelectorArgumentListAST;
diff --git a/src/shared/cplusplus/Keywords.cpp b/src/shared/cplusplus/Keywords.cpp
index d42ca3795a4..7ce723e3cc9 100644
--- a/src/shared/cplusplus/Keywords.cpp
+++ b/src/shared/cplusplus/Keywords.cpp
@@ -1198,7 +1198,7 @@ static inline int classify11(const char *s, bool q) {
   return T_IDENTIFIER;
 }
 
-static inline int classify12(const char *s, bool) {
+static inline int classify12(const char *s, bool q) {
   if (s[0] == '_') {
     if (s[1] == '_') {
       if (s[2] == 'v') {
@@ -1224,6 +1224,31 @@ static inline int classify12(const char *s, bool) {
       }
     }
   }
+  else if (q && s[0] == 'Q') {
+    if (s[1] == '_') {
+      if (s[2] == 'I') {
+        if (s[3] == 'N') {
+          if (s[4] == 'T') {
+            if (s[5] == 'E') {
+              if (s[6] == 'R') {
+                if (s[7] == 'F') {
+                  if (s[8] == 'A') {
+                    if (s[9] == 'C') {
+                      if (s[10] == 'E') {
+                        if (s[11] == 'S') {
+                          return T_Q_INTERFACES;
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
   else if (s[0] == 'd') {
     if (s[1] == 'y') {
       if (s[2] == 'n') {
diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp
index 93b30251c7c..95372cbad5b 100644
--- a/src/shared/cplusplus/Parser.cpp
+++ b/src/shared/cplusplus/Parser.cpp
@@ -293,6 +293,7 @@ void Parser::skipUntilDeclaration()
         case T_Q_PROPERTY:
         case T_Q_ENUMS:
         case T_Q_FLAGS:
+        case T_Q_INTERFACES:
 
         // Qt function specifiers
         case T_Q_SIGNAL:
@@ -1942,6 +1943,78 @@ bool Parser::parseQtFlags(DeclarationAST *&node)
     return true;
 }
 
+// class-specifier ::=
+//   c++-class-specifier
+//   q-tag
+//   q-enums-of-flags
+//   q-class-info
+//   q-interfaces
+//   q-private-slot
+//
+// declaration ::=
+//   c++-declaration
+//   q-declare-interface
+//   q-declare-metatype
+//
+// q-tag ::=
+//   Q_OBJECT
+//   Q_GADGET
+//
+// q-enums-or-flags ::=
+//   (Q_ENUMS | Q_FLAGS) LPAREN name+ RPAREN
+//
+// q-class-info ::=
+//   Q_CLASS_INFO LPAREN string-literal COMMA STRING_LITERAL RPAREN
+//   Q_CLASS_INFO LPAREN string-literal COMMA IDENTIFIER LPAREN STRING_LITERAL RPAREN RPAREN
+
+// q-interfaces ::=
+//   Q_INTERFACES LPAREN (name q-constraints)* RPAREN
+//
+// q-constraints ::=
+//   (COLON name)*
+bool Parser::parseQtInterfaces(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_Q_INTERFACES)
+        return false;
+
+    QtInterfacesDeclarationAST *ast = new (_pool) QtInterfacesDeclarationAST;
+    ast->interfaces_token = consumeToken();
+    match(T_LPAREN, &ast->lparen_token);
+    for (QtInterfaceNameListAST **iter = &ast->interface_name_list; LA() && LA() != T_RPAREN; iter = &(*iter)->next) {
+        NameAST *name_ast = 0;
+        if (!parseName(name_ast))
+            break;
+        *iter = new (_pool) QtInterfaceNameListAST;
+        (*iter)->value = new (_pool) QtInterfaceNameAST;
+        (*iter)->value->interface_name = name_ast;
+        for (NameListAST **iter2 = &(*iter)->value->constraint_list; LA() && LA() == T_COLON; iter2 = &(*iter2)->next) {
+            /*unsigned colon_token =*/ consumeToken();
+            NameAST *name_ast2 = 0;
+            if (!parseName(name_ast2))
+                break;
+            *iter2 = new (_pool) NameListAST;
+            (*iter2)->value = name_ast2;
+        }
+    }
+
+    match(T_RPAREN, &ast->rparen_token);
+    node = ast;
+    return true;
+}
+
+// q-private-slot ::=
+//   Q_PRIVATE_SLOT LPAREN IDENTIFIER (LPAREN RPAREN)? COMMA q-function-declaration RPAREN
+//
+// q-function-declaration ::=
+//   decl-specifier-list declarator   [+ check for the function-declarator]
+//
+// q-declare-interface ::=
+//   Q_DECLARE_INTERFACE LPAREN name COMMA (STRING_LITERAL | IDENTIFIER) RPAREN
+//
+// q-declare-metatype ::=
+//   Q_DECLARE_METATYPE LPAREN name RPAREN SEMICOLON? [warning]
+
 bool Parser::parseMemberSpecification(DeclarationAST *&node)
 {
     DEBUG_THIS_RULE();
@@ -1971,6 +2044,9 @@ bool Parser::parseMemberSpecification(DeclarationAST *&node)
     case T_Q_FLAGS:
         return parseQtFlags(node);
 
+    case T_Q_INTERFACES:
+        return parseQtInterfaces(node);
+
     default:
         return parseSimpleDeclaration(node, /*acceptStructDeclarator=*/true);
     } // switch
diff --git a/src/shared/cplusplus/Parser.h b/src/shared/cplusplus/Parser.h
index e10be3ac81d..1ae857ea81e 100644
--- a/src/shared/cplusplus/Parser.h
+++ b/src/shared/cplusplus/Parser.h
@@ -81,6 +81,7 @@ public:
     bool parseQtPropertyDeclaration(DeclarationAST *&node);
     bool parseQtEnumDeclaration(DeclarationAST *&node);
     bool parseQtFlags(DeclarationAST *&node);
+    bool parseQtInterfaces(DeclarationAST *&node);
     bool parseAdditiveExpression(ExpressionAST *&node);
     bool parseAndExpression(ExpressionAST *&node);
     bool parseAsmDefinition(DeclarationAST *&node);
diff --git a/src/shared/cplusplus/Token.cpp b/src/shared/cplusplus/Token.cpp
index 9dfe80b1549..cafce02eacb 100644
--- a/src/shared/cplusplus/Token.cpp
+++ b/src/shared/cplusplus/Token.cpp
@@ -93,7 +93,7 @@ static const char *token_names[] = {
 
     ("SIGNAL"), ("SLOT"), ("Q_SIGNAL"), ("Q_SLOT"), ("signals"), ("slots"),
     ("Q_FOREACH"), ("Q_D"), ("Q_Q"),
-    ("Q_INVOKABLE"), ("Q_PROPERTY"), ("Q_ENUMS"), ("Q_FLAGS")
+    ("Q_INVOKABLE"), ("Q_PROPERTY"), ("Q_INTERFACES"), ("Q_ENUMS"), ("Q_FLAGS")
 };
 
 Token::Token() :
diff --git a/src/shared/cplusplus/Token.h b/src/shared/cplusplus/Token.h
index 7644a31b821..e71d25bf62a 100644
--- a/src/shared/cplusplus/Token.h
+++ b/src/shared/cplusplus/Token.h
@@ -240,6 +240,7 @@ enum Kind {
     T_Q_Q,
     T_Q_INVOKABLE,
     T_Q_PROPERTY,
+    T_Q_INTERFACES,
     T_Q_ENUMS,
     T_Q_FLAGS,
     T_LAST_KEYWORD = T_Q_FLAGS,
-- 
GitLab