diff --git a/src/shared/cplusplus/AST.cpp b/src/shared/cplusplus/AST.cpp
index 6a72e3b90a7c29df9ec79aaf07e882b92496517a..eca2e2009612b881d93915120920b3e2771beb5e 100644
--- a/src/shared/cplusplus/AST.cpp
+++ b/src/shared/cplusplus/AST.cpp
@@ -2104,4 +2104,23 @@ unsigned ObjCMessageArgumentAST::lastToken() const
     return parameter_key_identifier + 1;
 }
 
+unsigned ObjCProtocolExpressionAST::firstToken() const
+{
+    return protocol_token;
+}
+
+unsigned ObjCProtocolExpressionAST::lastToken() const
+{
+    if (rparen_token)
+        return rparen_token + 1;
+
+    if (identifier_token)
+        return identifier_token + 1;
+
+    if (lparen_token)
+        return lparen_token + 1;
+
+    return protocol_token + 1;
+}
+
 CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h
index 393126c9d47bfb4044b00d4ebea856430b3ee583..981bb29b159d278c00977daf041f5f4c1d352ca3 100644
--- a/src/shared/cplusplus/AST.h
+++ b/src/shared/cplusplus/AST.h
@@ -2653,6 +2653,27 @@ protected:
     virtual void accept0(ASTVisitor *visitor);
 };
 
+class CPLUSPLUS_EXPORT ObjCProtocolExpressionAST: public ExpressionAST
+{
+public:
+    unsigned protocol_token;
+    unsigned lparen_token;
+    unsigned identifier_token;
+    unsigned rparen_token;
+
+public:
+    virtual ObjCProtocolExpressionAST *asObjCProtocolExpression()
+    { return this; }
+
+    virtual unsigned firstToken() const;
+    virtual unsigned lastToken() const;
+
+    virtual ObjCProtocolExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+    virtual void accept0(ASTVisitor *visitor);
+};
+
 CPLUSPLUS_END_NAMESPACE
 CPLUSPLUS_END_HEADER
 
diff --git a/src/shared/cplusplus/ASTClone.cpp b/src/shared/cplusplus/ASTClone.cpp
index 5065cfdd230d7f80546a220bdffaf859d1c12a60..e12967651da0d8521e685dda854ba82d6b76054e 100644
--- a/src/shared/cplusplus/ASTClone.cpp
+++ b/src/shared/cplusplus/ASTClone.cpp
@@ -1311,4 +1311,14 @@ ObjCMessageArgumentAST *ObjCMessageArgumentAST::clone(MemoryPool *pool) const
     return ast;
 }
 
+ObjCProtocolExpressionAST *ObjCProtocolExpressionAST::clone(MemoryPool *pool) const
+{
+    ObjCProtocolExpressionAST *ast = new (pool) ObjCProtocolExpressionAST;
+    ast->protocol_token = protocol_token;
+    ast->lparen_token = lparen_token;
+    ast->identifier_token = identifier_token;
+    ast->rparen_token = rparen_token;
+    return ast;
+}
+
 CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/ASTVisit.cpp b/src/shared/cplusplus/ASTVisit.cpp
index 0f2052127d8068c4a03984ba19f5f5034e0c5cc3..1980ec78f9fde1d19c690d29ae2f6bdddb34f86b 100644
--- a/src/shared/cplusplus/ASTVisit.cpp
+++ b/src/shared/cplusplus/ASTVisit.cpp
@@ -1234,4 +1234,13 @@ void ObjCMessageArgumentAST::accept0(ASTVisitor *visitor)
     visitor->endVisit(this);
 }
 
+void ObjCProtocolExpressionAST::accept0(ASTVisitor *visitor)
+{
+    if (visitor->visit(this)) {
+        // visit ObjCProtocolExpressionAST
+        // visit ExpressionAST
+    }
+    visitor->endVisit(this);
+}
+
 CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/ASTVisitor.h b/src/shared/cplusplus/ASTVisitor.h
index 4b0672cbc1d9ba519a65f56e8610cdcd0df44910..6509235f44e2ca1ce2b90446009ff37aa10520e8 100644
--- a/src/shared/cplusplus/ASTVisitor.h
+++ b/src/shared/cplusplus/ASTVisitor.h
@@ -206,6 +206,7 @@ public:
     virtual bool visit(ObjCMessageExpressionAST *) { return true; }
     virtual bool visit(ObjCMessageArgumentListAST *) { return true; }
     virtual bool visit(ObjCMessageArgumentAST *) { return true; }
+    virtual bool visit(ObjCProtocolExpressionAST *) { return true; }
 
     virtual bool visit(DeclarationListAST *) { return true; }
     virtual void endVisit(DeclarationListAST *) { }
@@ -323,6 +324,7 @@ public:
     virtual void endVisit(ObjCMessageExpressionAST *) { }
     virtual void endVisit(ObjCMessageArgumentListAST *) { }
     virtual void endVisit(ObjCMessageArgumentAST *) { }
+    virtual void endVisit(ObjCProtocolExpressionAST *) { }
 
 private:
     Control *_control;
diff --git a/src/shared/cplusplus/ASTfwd.h b/src/shared/cplusplus/ASTfwd.h
index e12393df6a88b580e6c7387082796b135e0a1e1f..a70ad55da5da8e5475c7cc5ad9517dadd02f8bb8 100644
--- a/src/shared/cplusplus/ASTfwd.h
+++ b/src/shared/cplusplus/ASTfwd.h
@@ -179,6 +179,7 @@ class ObjCProtocolRefsAST;
 class ObjCMessageExpressionAST;
 class ObjCMessageArgumentListAST;
 class ObjCMessageArgumentAST;
+class ObjCProtocolExpressionAST;
 
 CPLUSPLUS_END_NAMESPACE
 CPLUSPLUS_END_HEADER
diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp
index ba705f9551bc2765f7ca873bb5e7d5ab68b60123..6ba6541068dd2d7d7870c8cc719d332b0cadead1 100644
--- a/src/shared/cplusplus/Parser.cpp
+++ b/src/shared/cplusplus/Parser.cpp
@@ -2849,16 +2849,17 @@ bool Parser::parseObjCEncodeExpression(ExpressionAST *&)
     return true;
 }
 
-bool Parser::parseObjCProtocolExpression(ExpressionAST *&)
+bool Parser::parseObjCProtocolExpression(ExpressionAST *&node)
 {
     if (LA() != T_AT_PROTOCOL)
         return false;
 
-    /*unsigned protocol_token = */ consumeToken();
-    unsigned lparen_token = 0, identifier_token = 0, rparen_token = 0;
-    match(T_LPAREN, &lparen_token);
-    match(T_IDENTIFIER, &identifier_token);
-    match(T_RPAREN, &rparen_token);
+    ObjCProtocolExpressionAST *ast = new (_pool) ObjCProtocolExpressionAST;
+    ast->protocol_token = consumeToken();
+    match(T_LPAREN, &(ast->lparen_token));
+    match(T_IDENTIFIER, &(ast->identifier_token));
+    match(T_RPAREN, &(ast->rparen_token));
+    node = ast;
     return true;
 }