diff --git a/src/shared/cplusplus/AST.cpp b/src/shared/cplusplus/AST.cpp
index 3da0dbf4646c07feb8d7067160bbcddfe7170bc0..6a72e3b90a7c29df9ec79aaf07e882b92496517a 100644
--- a/src/shared/cplusplus/AST.cpp
+++ b/src/shared/cplusplus/AST.cpp
@@ -2057,11 +2057,51 @@ unsigned ObjCMessageExpressionAST::firstToken() const
 
 unsigned ObjCMessageExpressionAST::lastToken() const
 {
-    if (rbracket_token) return rbracket_token + 1;
+    if (rbracket_token)
+        return rbracket_token + 1;
 
-    // FIXME: TODO
+    if (receiver_expression)
+        return receiver_expression->lastToken();
+
+    if (argument_list)
+        return argument_list->lastToken();
 
     return lbracket_token + 1;
 }
 
+unsigned ObjCMessageArgumentListAST::firstToken() const
+{
+    if (arg)
+        return arg->firstToken();
+    // ### assert?
+    return 0;
+}
+
+unsigned ObjCMessageArgumentListAST::lastToken() const
+{
+    for (const ObjCMessageArgumentListAST *it = this; it; it = it->next) {
+        if (! it->next && it->arg) {
+            return it->arg->lastToken();
+        }
+    }
+    // ### assert?
+    return 0;
+}
+
+unsigned ObjCMessageArgumentAST::firstToken() const
+{
+    return parameter_key_identifier;
+}
+
+unsigned ObjCMessageArgumentAST::lastToken() const
+{
+    if (parameter_value_expression)
+        return parameter_value_expression->lastToken();
+
+    if (colon_token)
+        return colon_token + 1;
+
+    return parameter_key_identifier + 1;
+}
+
 CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h
index 2e56fc52645b83d1abcaa508553f1ff00296c8a6..393126c9d47bfb4044b00d4ebea856430b3ee583 100644
--- a/src/shared/cplusplus/AST.h
+++ b/src/shared/cplusplus/AST.h
@@ -2593,11 +2593,51 @@ protected:
     virtual void accept0(ASTVisitor *visitor);
 };
 
+class CPLUSPLUS_EXPORT ObjCMessageArgumentAST: public AST
+{
+public:
+    unsigned parameter_key_identifier;
+    unsigned colon_token;
+    ExpressionAST *parameter_value_expression;
+
+public:
+    virtual ObjCMessageArgumentAST *asObjCMessageArgument()
+    { return this; }
+
+    virtual unsigned firstToken() const;
+    virtual unsigned lastToken() const;
+
+    virtual ObjCMessageArgumentAST *clone(MemoryPool *pool) const;
+
+protected:
+    virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ObjCMessageArgumentListAST: public AST
+{
+public:
+    ObjCMessageArgumentAST *arg;
+    ObjCMessageArgumentListAST *next;
+
+public:
+    virtual ObjCMessageArgumentListAST *asObjCMessageArgumentList()
+    { return this; }
+
+    virtual unsigned firstToken() const;
+    virtual unsigned lastToken() const;
+
+    virtual ObjCMessageArgumentListAST *clone(MemoryPool *pool) const;
+
+protected:
+    virtual void accept0(ASTVisitor *visitor);
+};
+
 class CPLUSPLUS_EXPORT ObjCMessageExpressionAST: public ExpressionAST
 {
 public:
     unsigned lbracket_token;
-    // ..
+    ExpressionAST *receiver_expression;
+    ObjCMessageArgumentListAST *argument_list;
     unsigned rbracket_token;
 
 public:
diff --git a/src/shared/cplusplus/ASTClone.cpp b/src/shared/cplusplus/ASTClone.cpp
index b8ceec183cab538f9a5debc587878c49cd1c9b09..5065cfdd230d7f80546a220bdffaf859d1c12a60 100644
--- a/src/shared/cplusplus/ASTClone.cpp
+++ b/src/shared/cplusplus/ASTClone.cpp
@@ -1288,9 +1288,27 @@ ObjCMessageExpressionAST *ObjCMessageExpressionAST::clone(MemoryPool *pool) cons
 {
     ObjCMessageExpressionAST *ast = new (pool) ObjCMessageExpressionAST;
     ast->lbracket_token = lbracket_token;
-    // FIXME: TODO
+    if (receiver_expression) ast->receiver_expression = receiver_expression->clone(pool);
+    if (argument_list) ast->argument_list = argument_list->clone(pool);
     ast->rbracket_token = rbracket_token;
     return ast;
 }
 
+ObjCMessageArgumentListAST *ObjCMessageArgumentListAST::clone(MemoryPool *pool) const
+{
+    ObjCMessageArgumentListAST *ast = new (pool) ObjCMessageArgumentListAST;
+    if (arg) ast->arg = arg->clone(pool);
+    if (next) ast->next = next->clone(pool);
+    return ast;
+}
+
+ObjCMessageArgumentAST *ObjCMessageArgumentAST::clone(MemoryPool *pool) const
+{
+    ObjCMessageArgumentAST *ast = new (pool) ObjCMessageArgumentAST;
+    ast->parameter_key_identifier = parameter_key_identifier;
+    ast->colon_token = colon_token;
+    if (parameter_value_expression) ast->parameter_value_expression = parameter_value_expression->clone(pool);
+    return ast;
+}
+
 CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/ASTVisit.cpp b/src/shared/cplusplus/ASTVisit.cpp
index c556b21015ea6c9899776b61b8e03db7569f30cf..0f2052127d8068c4a03984ba19f5f5034e0c5cc3 100644
--- a/src/shared/cplusplus/ASTVisit.cpp
+++ b/src/shared/cplusplus/ASTVisit.cpp
@@ -1200,7 +1200,36 @@ void ObjCProtocolRefsAST::accept0(ASTVisitor *visitor)
 void ObjCMessageExpressionAST::accept0(ASTVisitor *visitor)
 {
     if (visitor->visit(this)) {
-        // FIXME: TODO
+        // visit ObjCMessageExpressionAST
+        if (receiver_expression)
+            accept(receiver_expression, visitor);
+        if (argument_list)
+            accept(argument_list, visitor);
+        // visit ExpressionAST
+    }
+    visitor->endVisit(this);
+}
+
+void ObjCMessageArgumentListAST::accept0(ASTVisitor *visitor)
+{
+    if (visitor->visit(this)) {
+        // visit ObjCMessageArgumentListAST
+        if (arg)
+            accept(arg, visitor);
+        if (next)
+            accept(next, visitor);
+        // visit AST
+    }
+    visitor->endVisit(this);
+}
+
+void ObjCMessageArgumentAST::accept0(ASTVisitor *visitor)
+{
+    if (visitor->visit(this)) {
+        // visit ObjCMessageArgumentAST
+        if (parameter_value_expression)
+            accept(parameter_value_expression, visitor);
+        // visit AST
     }
     visitor->endVisit(this);
 }
diff --git a/src/shared/cplusplus/ASTVisitor.h b/src/shared/cplusplus/ASTVisitor.h
index fd8c21971f3427c6e9fb467c33363ac1ebd083ed..4b0672cbc1d9ba519a65f56e8610cdcd0df44910 100644
--- a/src/shared/cplusplus/ASTVisitor.h
+++ b/src/shared/cplusplus/ASTVisitor.h
@@ -204,6 +204,8 @@ public:
     virtual bool visit(ObjCProtocolDefinitionAST *) { return true; }
     virtual bool visit(ObjCProtocolRefsAST *) { return true; }
     virtual bool visit(ObjCMessageExpressionAST *) { return true; }
+    virtual bool visit(ObjCMessageArgumentListAST *) { return true; }
+    virtual bool visit(ObjCMessageArgumentAST *) { return true; }
 
     virtual bool visit(DeclarationListAST *) { return true; }
     virtual void endVisit(DeclarationListAST *) { }
@@ -319,6 +321,8 @@ public:
     virtual void endVisit(ObjCProtocolDefinitionAST *) { }
     virtual void endVisit(ObjCProtocolRefsAST *) { }
     virtual void endVisit(ObjCMessageExpressionAST *) { }
+    virtual void endVisit(ObjCMessageArgumentListAST *) { }
+    virtual void endVisit(ObjCMessageArgumentAST *) { }
 
 private:
     Control *_control;
diff --git a/src/shared/cplusplus/ASTfwd.h b/src/shared/cplusplus/ASTfwd.h
index a4662226fa5121395cdbd8b9a636119fc19568e3..e12393df6a88b580e6c7387082796b135e0a1e1f 100644
--- a/src/shared/cplusplus/ASTfwd.h
+++ b/src/shared/cplusplus/ASTfwd.h
@@ -177,6 +177,8 @@ class ObjCClassInterfaceDeclarationAST;
 class ObjCCategoryInterfaceDeclarationAST;
 class ObjCProtocolRefsAST;
 class ObjCMessageExpressionAST;
+class ObjCMessageArgumentListAST;
+class ObjCMessageArgumentAST;
 
 CPLUSPLUS_END_NAMESPACE
 CPLUSPLUS_END_HEADER
diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp
index 635c337ced49d4fc364c5dbb7602c39ce01f19cd..cf091cfa0e06a68de2ea2cb82e6031d70c34f676 100644
--- a/src/shared/cplusplus/Parser.cpp
+++ b/src/shared/cplusplus/Parser.cpp
@@ -2914,21 +2914,20 @@ bool Parser::parseObjCMessageExpression(ExpressionAST *&node)
     ObjCMessageExpressionAST *ast = new (_pool) ObjCMessageExpressionAST;
     ast->lbracket_token = consumeToken();
 
-    parseObjCMessageReceiver();
-    parseObjCMessageArguments();
+    parseObjCMessageReceiver(ast->receiver_expression);
+    parseObjCMessageArguments(ast->argument_list);
 
     match(T_RBRACKET, &(ast->rbracket_token));
     node = ast;
     return true;
 }
 
-bool Parser::parseObjCMessageReceiver()
+bool Parser::parseObjCMessageReceiver(ExpressionAST *&node)
 {
-    ExpressionAST *expression = 0;
-    return parseExpression(expression);
+    return parseExpression(node);
 }
 
-bool Parser::parseObjCMessageArguments()
+bool Parser::parseObjCMessageArguments(ObjCMessageArgumentListAST *& /*node*/)
 {
     if (LA() == T_RBRACKET)
         return false; // nothing to do.
diff --git a/src/shared/cplusplus/Parser.h b/src/shared/cplusplus/Parser.h
index 8d02e429555a35bb935db4fbb8f41dc42b3e4c53..4d6af741bfda9e3b71584d22226bcc3f690a98db 100644
--- a/src/shared/cplusplus/Parser.h
+++ b/src/shared/cplusplus/Parser.h
@@ -225,8 +225,8 @@ public:
     bool parseObjCStringLiteral(ExpressionAST *&node);
     bool parseObjCMethodSignature();
     bool parseObjCMessageExpression(ExpressionAST *&node);
-    bool parseObjCMessageReceiver();
-    bool parseObjCMessageArguments();
+    bool parseObjCMessageReceiver(ExpressionAST *&node);
+    bool parseObjCMessageArguments(ObjCMessageArgumentListAST *&node);
     bool parseObjCSelectorArgs();
     bool parseObjCMethodDefinitionList();
     bool parseObjCMethodDefinition();