From 4a0da2c6f2663d9469bfd929fa682b6df7d42ab7 Mon Sep 17 00:00:00 2001
From: Erik Verbruggen <erik.verbruggen@nokia.com>
Date: Fri, 31 Jul 2009 16:03:48 +0200
Subject: [PATCH] Added Semantic checks for ObjC methods.

---
 src/libs/cplusplus/NamePrettyPrinter.cpp      | 17 ++++++
 src/libs/cplusplus/NamePrettyPrinter.h        |  1 +
 src/libs/cplusplus/OverviewModel.cpp          |  6 ++
 src/shared/cplusplus/AST.cpp                  | 11 ++--
 src/shared/cplusplus/AST.h                    |  3 +-
 src/shared/cplusplus/ASTClone.cpp             |  3 +-
 src/shared/cplusplus/ASTVisit.cpp             |  9 +--
 .../cplusplus/CPlusPlusForwardDeclarations.h  |  2 +
 src/shared/cplusplus/CheckDeclaration.cpp     | 30 ++++++++++
 src/shared/cplusplus/CheckDeclaration.h       |  1 +
 src/shared/cplusplus/CheckExpression.cpp      | 25 ++++++++
 src/shared/cplusplus/CheckExpression.h        |  5 ++
 src/shared/cplusplus/CheckName.cpp            |  6 +-
 src/shared/cplusplus/Control.cpp              | 40 +++++++++++++
 src/shared/cplusplus/Control.h                |  4 ++
 src/shared/cplusplus/Name.cpp                 |  3 +
 src/shared/cplusplus/Name.h                   |  3 +
 src/shared/cplusplus/NameVisitor.h            |  1 +
 src/shared/cplusplus/Names.cpp                | 57 +++++++++++++++++++
 src/shared/cplusplus/Names.h                  | 33 +++++++++++
 src/shared/cplusplus/Parser.cpp               | 52 +++++++++++------
 src/shared/cplusplus/Parser.h                 |  4 +-
 22 files changed, 281 insertions(+), 35 deletions(-)

diff --git a/src/libs/cplusplus/NamePrettyPrinter.cpp b/src/libs/cplusplus/NamePrettyPrinter.cpp
index 75aa582cded..788c418c09a 100644
--- a/src/libs/cplusplus/NamePrettyPrinter.cpp
+++ b/src/libs/cplusplus/NamePrettyPrinter.cpp
@@ -253,3 +253,20 @@ void NamePrettyPrinter::visit(QualifiedNameId *name)
         _name += operator()(name->nameAt(index));
     }
 }
+
+void NamePrettyPrinter::visit(SelectorNameId *name)
+{
+    for (unsigned i = 0; i < name->nameCount(); ++i) {
+        Name *n = name->nameAt(i);
+        if (!n)
+            continue;
+
+        Identifier *id = n->identifier();
+        if (id) {
+            _name += QString::fromLatin1(id->chars(), id->size());
+
+            if (name->hasArguments() || name->nameCount() > 1)
+                _name += ':';
+        }
+    }
+}
diff --git a/src/libs/cplusplus/NamePrettyPrinter.h b/src/libs/cplusplus/NamePrettyPrinter.h
index 2e0ef2c9b1c..6704099009c 100644
--- a/src/libs/cplusplus/NamePrettyPrinter.h
+++ b/src/libs/cplusplus/NamePrettyPrinter.h
@@ -55,6 +55,7 @@ protected:
     virtual void visit(OperatorNameId *name);
     virtual void visit(ConversionNameId *name);
     virtual void visit(QualifiedNameId *name);
+    virtual void visit(SelectorNameId *name);
 
 private:
     const Overview *_overview;
diff --git a/src/libs/cplusplus/OverviewModel.cpp b/src/libs/cplusplus/OverviewModel.cpp
index 008fb97abe9..ed119824af9 100644
--- a/src/libs/cplusplus/OverviewModel.cpp
+++ b/src/libs/cplusplus/OverviewModel.cpp
@@ -164,6 +164,12 @@ QVariant OverviewModel::data(const QModelIndex &index, int role) const
         QString name = _overview.prettyName(symbol->name());
         if (name.isEmpty())
             name = QLatin1String("anonymous");
+        if (symbol->isObjCForwardClassDeclaration())
+            name = QLatin1String("@class ") + name;
+        if (symbol->isObjCForwardProtocolDeclaration() || symbol->isObjCProtocol())
+            name = QLatin1String("@protocol ") + name;
+        if (symbol->isObjCClass())
+            name = QLatin1String("@interface ") + name;
         if (! symbol->isScopedSymbol() || symbol->isFunction()) {
             QString type = _overview.prettyType(symbol->type());
             if (! type.isEmpty()) {
diff --git a/src/shared/cplusplus/AST.cpp b/src/shared/cplusplus/AST.cpp
index 0a16fa774ca..cba0a7a39dc 100644
--- a/src/shared/cplusplus/AST.cpp
+++ b/src/shared/cplusplus/AST.cpp
@@ -2080,6 +2080,9 @@ unsigned ObjCMessageExpressionAST::lastToken() const
     if (receiver_expression)
         return receiver_expression->lastToken();
 
+    if (selector)
+        return selector->lastToken();
+
     if (argument_list)
         return argument_list->lastToken();
 
@@ -2107,7 +2110,7 @@ unsigned ObjCMessageArgumentListAST::lastToken() const
 
 unsigned ObjCMessageArgumentAST::firstToken() const
 {
-    return parameter_key_identifier;
+    return parameter_value_expression->firstToken();
 }
 
 unsigned ObjCMessageArgumentAST::lastToken() const
@@ -2115,10 +2118,8 @@ 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;
+    // ### assert?
+    return 0;
 }
 
 unsigned ObjCProtocolExpressionAST::firstToken() const
diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h
index d9e54130287..fb84d4d0a91 100644
--- a/src/shared/cplusplus/AST.h
+++ b/src/shared/cplusplus/AST.h
@@ -2644,8 +2644,6 @@ protected:
 class CPLUSPLUS_EXPORT ObjCMessageArgumentAST: public AST
 {
 public:
-    unsigned parameter_key_identifier;
-    unsigned colon_token;
     ExpressionAST *parameter_value_expression;
 
 public:
@@ -2685,6 +2683,7 @@ class CPLUSPLUS_EXPORT ObjCMessageExpressionAST: public ExpressionAST
 public:
     unsigned lbracket_token;
     ExpressionAST *receiver_expression;
+    ObjCSelectorAST *selector;
     ObjCMessageArgumentListAST *argument_list;
     unsigned rbracket_token;
 
diff --git a/src/shared/cplusplus/ASTClone.cpp b/src/shared/cplusplus/ASTClone.cpp
index 1fbb5a651b1..87e74d9ee48 100644
--- a/src/shared/cplusplus/ASTClone.cpp
+++ b/src/shared/cplusplus/ASTClone.cpp
@@ -1295,6 +1295,7 @@ ObjCMessageExpressionAST *ObjCMessageExpressionAST::clone(MemoryPool *pool) cons
     ObjCMessageExpressionAST *ast = new (pool) ObjCMessageExpressionAST;
     ast->lbracket_token = lbracket_token;
     if (receiver_expression) ast->receiver_expression = receiver_expression->clone(pool);
+    if (selector) ast->selector = selector->clone(pool);
     if (argument_list) ast->argument_list = argument_list->clone(pool);
     ast->rbracket_token = rbracket_token;
     return ast;
@@ -1311,8 +1312,6 @@ ObjCMessageArgumentListAST *ObjCMessageArgumentListAST::clone(MemoryPool *pool)
 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;
 }
diff --git a/src/shared/cplusplus/ASTVisit.cpp b/src/shared/cplusplus/ASTVisit.cpp
index f258ac1125e..a76d80df6bb 100644
--- a/src/shared/cplusplus/ASTVisit.cpp
+++ b/src/shared/cplusplus/ASTVisit.cpp
@@ -1220,6 +1220,8 @@ void ObjCMessageExpressionAST::accept0(ASTVisitor *visitor)
         // visit ObjCMessageExpressionAST
         if (receiver_expression)
             accept(receiver_expression, visitor);
+        if (selector)
+            accept(selector, visitor);
         if (argument_list)
             accept(argument_list, visitor);
         // visit ExpressionAST
@@ -1231,10 +1233,9 @@ void ObjCMessageArgumentListAST::accept0(ASTVisitor *visitor)
 {
     if (visitor->visit(this)) {
         // visit ObjCMessageArgumentListAST
-        if (arg)
-            accept(arg, visitor);
-        if (next)
-            accept(next, visitor);
+        for (ObjCMessageArgumentListAST *it = this; it; it = it->next)
+            if (it->arg)
+                accept(it->arg, visitor);
         // visit AST
     }
     visitor->endVisit(this);
diff --git a/src/shared/cplusplus/CPlusPlusForwardDeclarations.h b/src/shared/cplusplus/CPlusPlusForwardDeclarations.h
index 76ee3061dc5..e85dda262f7 100644
--- a/src/shared/cplusplus/CPlusPlusForwardDeclarations.h
+++ b/src/shared/cplusplus/CPlusPlusForwardDeclarations.h
@@ -100,6 +100,7 @@ class DestructorNameId;
 class OperatorNameId;
 class ConversionNameId;
 class QualifiedNameId;
+class SelectorNameId;
 
 // types
 class FullySpecifiedType;
@@ -138,6 +139,7 @@ class ObjCClass;
 class ObjCForwardClassDeclaration;
 class ObjCProtocol;
 class ObjCForwardProtocolDeclaration;
+class ObjCMethod;
 
 CPLUSPLUS_END_NAMESPACE
 CPLUSPLUS_END_HEADER
diff --git a/src/shared/cplusplus/CheckDeclaration.cpp b/src/shared/cplusplus/CheckDeclaration.cpp
index 1a9877db156..f3157e7bc67 100644
--- a/src/shared/cplusplus/CheckDeclaration.cpp
+++ b/src/shared/cplusplus/CheckDeclaration.cpp
@@ -598,6 +598,36 @@ bool CheckDeclaration::visit(ObjCMethodDeclarationAST *ast)
     return false;
 }
 
+bool CheckDeclaration::visit(ObjCMethodDefinitionAST *ast)
+{
+    if (!ast->method_prototype)
+        return false;
+
+    FullySpecifiedType ty = semantic()->check(ast->method_prototype, _scope);
+    Function *fun = ty.type()->asFunctionType();
+    if (!fun)
+        return false;
+
+    Declaration *symbol = control()->newDeclaration(ast->firstToken(), fun->name());
+    symbol->setStartOffset(tokenAt(ast->firstToken()).offset);
+    symbol->setEndOffset(tokenAt(ast->lastToken()).offset);
+
+    symbol->setType(fun->returnType());
+
+    symbol->setVisibility(semantic()->currentVisibility());
+
+    if (semantic()->isObjCClassMethod(ast->method_prototype->method_type_token))
+        symbol->setStorage(Symbol::Static);
+
+    _scope->enterSymbol(symbol);
+
+     if (! semantic()->skipFunctionBodies()) {
+        semantic()->check(ast->function_body, fun->members());
+    }
+
+    return false;
+}
+
 bool CheckDeclaration::visit(ObjCVisibilityDeclarationAST *ast)
 {
     int accessSpecifier = tokenKind(ast->visibility_token);
diff --git a/src/shared/cplusplus/CheckDeclaration.h b/src/shared/cplusplus/CheckDeclaration.h
index 97c4d5ff449..b1880c5377f 100644
--- a/src/shared/cplusplus/CheckDeclaration.h
+++ b/src/shared/cplusplus/CheckDeclaration.h
@@ -96,6 +96,7 @@ protected:
     virtual bool visit(ObjCClassDeclarationAST *ast);
     virtual bool visit(ObjCClassInterfaceDefinitionAST *ast);
     virtual bool visit(ObjCMethodDeclarationAST *ast);
+    virtual bool visit(ObjCMethodDefinitionAST *ast);
     virtual bool visit(ObjCVisibilityDeclarationAST *ast);
 
 private:
diff --git a/src/shared/cplusplus/CheckExpression.cpp b/src/shared/cplusplus/CheckExpression.cpp
index 25cfe8ba43a..ac93a1a9de0 100644
--- a/src/shared/cplusplus/CheckExpression.cpp
+++ b/src/shared/cplusplus/CheckExpression.cpp
@@ -383,4 +383,29 @@ bool CheckExpression::visit(MemberAccessAST *ast)
     return false;
 }
 
+bool CheckExpression::visit(ObjCMessageExpressionAST *ast)
+{
+    semantic()->check(ast->receiver_expression, _scope);
+
+    if (Name *name = semantic()->check(ast->selector, _scope))
+        _scope->addUse(ast->selector->firstToken(), name);
+
+    accept(ast->argument_list);
+    return false;
+}
+
+bool CheckExpression::visit(ObjCEncodeExpressionAST * /*ast*/)
+{
+    // TODO: visit the type name, but store the type here? (EV)
+    return true;
+}
+
+bool CheckExpression::visit(ObjCSelectorExpressionAST *ast)
+{
+    if (Name *name = semantic()->check(ast->selector, _scope))
+        _scope->addUse(ast->selector->firstToken(), name);
+
+    return false;
+}
+
 CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/CheckExpression.h b/src/shared/cplusplus/CheckExpression.h
index dad53ed3b76..41c3393d7ae 100644
--- a/src/shared/cplusplus/CheckExpression.h
+++ b/src/shared/cplusplus/CheckExpression.h
@@ -110,6 +110,11 @@ protected:
     virtual bool visit(PostIncrDecrAST *ast);
     virtual bool visit(MemberAccessAST *ast);
 
+    // ObjC
+    virtual bool visit(ObjCMessageExpressionAST *ast);
+    virtual bool visit(ObjCEncodeExpressionAST *ast);
+    virtual bool visit(ObjCSelectorExpressionAST *ast);
+
 private:
     ExpressionAST *_expression;
     FullySpecifiedType _fullySpecifiedType;
diff --git a/src/shared/cplusplus/CheckName.cpp b/src/shared/cplusplus/CheckName.cpp
index 48ab067f03b..0fad66cccf9 100644
--- a/src/shared/cplusplus/CheckName.cpp
+++ b/src/shared/cplusplus/CheckName.cpp
@@ -376,8 +376,10 @@ bool CheckName::visit(TemplateIdAST *ast)
 
 bool CheckName::visit(ObjCSelectorWithoutArgumentsAST *ast)
 {
+    std::vector<Name *> names;
     Identifier *id = identifier(ast->name_token);
-    _name = control()->nameId(id);
+    names.push_back(control()->nameId(id));
+    _name = control()->selectorNameId(&names[0], names.size(), false);
     ast->selector_name = _name;
 
     return false;
@@ -392,7 +394,7 @@ bool CheckName::visit(ObjCSelectorWithArgumentsAST *ast)
 
         names.push_back(name);
     }
-    _name = control()->qualifiedNameId(&names[0], names.size(), false);
+    _name = control()->selectorNameId(&names[0], names.size(), true);
     ast->selector_name = _name;
 
     return false;
diff --git a/src/shared/cplusplus/Control.cpp b/src/shared/cplusplus/Control.cpp
index 49f965f7da3..96a67196119 100644
--- a/src/shared/cplusplus/Control.cpp
+++ b/src/shared/cplusplus/Control.cpp
@@ -196,6 +196,15 @@ public:
         return it->second;
     }
 
+    SelectorNameId *findOrInsertSelectorNameId(const std::vector<Name *> &names, bool hasArguments)
+    {
+        const SelectorNameIdKey key(names, hasArguments);
+        std::map<SelectorNameIdKey, SelectorNameId *>::iterator it = selectorNameIds.lower_bound(key);
+        if (it == selectorNameIds.end() || it->first != key)
+            it = selectorNameIds.insert(it, std::make_pair(key, new SelectorNameId(&names[0], names.size(), hasArguments)));
+        return it->second;
+    }
+
     IntegerType *findOrInsertIntegerType(int kind)
     {
         const int key = int(kind);
@@ -423,6 +432,27 @@ public:
         }
     };
 
+    struct SelectorNameIdKey {
+        std::vector<Name *> _names;
+        bool _hasArguments;
+
+        SelectorNameIdKey(const std::vector<Name *> &names, bool hasArguments): _names(names), _hasArguments(hasArguments) {}
+
+        bool operator==(const SelectorNameIdKey &other) const
+        { return _names == other._names && _hasArguments == other._hasArguments; }
+
+        bool operator!=(const SelectorNameIdKey &other) const
+        { return !operator==(other); }
+
+        bool operator<(const SelectorNameIdKey &other) const
+        {
+            if (_hasArguments == other._hasArguments)
+                return std::lexicographical_compare(_names.begin(), _names.end(), other._names.begin(), other._names.end());
+            else
+                return _hasArguments < other._hasArguments;
+        }
+    };
+
     struct ArrayKey {
         FullySpecifiedType type;
         size_t size;
@@ -491,6 +521,7 @@ public:
     std::map<FullySpecifiedType, ConversionNameId *> conversionNameIds;
     std::map<TemplateNameIdKey, TemplateNameId *> templateNameIds;
     std::map<QualifiedNameIdKey, QualifiedNameId *> qualifiedNameIds;
+    std::map<SelectorNameIdKey, SelectorNameId *> selectorNameIds;
 
     // types
     VoidType voidType;
@@ -615,6 +646,15 @@ QualifiedNameId *Control::qualifiedNameId(Name *const *names,
     return d->findOrInsertQualifiedNameId(classOrNamespaceNames, isGlobal);
 }
 
+SelectorNameId *Control::selectorNameId(Name *const *names,
+                                        unsigned nameCount,
+                                        bool hasArguments)
+{
+    std::vector<Name *> selectorNames(names, names + nameCount);
+    return d->findOrInsertSelectorNameId(selectorNames, hasArguments);
+}
+
+
 VoidType *Control::voidType()
 { return &d->voidType; }
 
diff --git a/src/shared/cplusplus/Control.h b/src/shared/cplusplus/Control.h
index a9b85b7baee..5e90e0947b9 100644
--- a/src/shared/cplusplus/Control.h
+++ b/src/shared/cplusplus/Control.h
@@ -89,6 +89,10 @@ public:
                                      unsigned nameCount,
                                      bool isGlobal = false);
 
+    SelectorNameId *selectorNameId(Name *const *names,
+                                   unsigned nameCount,
+                                   bool hasArguments);
+
     /// Returns a Type object of type VoidType.
     VoidType *voidType();
 
diff --git a/src/shared/cplusplus/Name.cpp b/src/shared/cplusplus/Name.cpp
index b3c9019f7d9..7420bd496bd 100644
--- a/src/shared/cplusplus/Name.cpp
+++ b/src/shared/cplusplus/Name.cpp
@@ -76,6 +76,9 @@ bool Name::isConversionNameId() const
 bool Name::isQualifiedNameId() const
 { return asQualifiedNameId() != 0; }
 
+bool Name::isSelectorNameId() const
+{ return asSelectorNameId() != 0; }
+
 void Name::accept(NameVisitor *visitor)
 {
     if (visitor->preVisit(this))
diff --git a/src/shared/cplusplus/Name.h b/src/shared/cplusplus/Name.h
index 145b3344b98..3604aca570a 100644
--- a/src/shared/cplusplus/Name.h
+++ b/src/shared/cplusplus/Name.h
@@ -71,6 +71,7 @@ public:
     bool isOperatorNameId() const;
     bool isConversionNameId() const;
     bool isQualifiedNameId() const;
+    bool isSelectorNameId() const;
 
     virtual const NameId *asNameId() const { return 0; }
     virtual const TemplateNameId *asTemplateNameId() const { return 0; }
@@ -78,6 +79,7 @@ public:
     virtual const OperatorNameId *asOperatorNameId() const { return 0; }
     virtual const ConversionNameId *asConversionNameId() const { return 0; }
     virtual const QualifiedNameId *asQualifiedNameId() const { return 0; }
+    virtual const SelectorNameId *asSelectorNameId() const { return 0; }
 
     virtual NameId *asNameId() { return 0; }
     virtual TemplateNameId *asTemplateNameId() { return 0; }
@@ -85,6 +87,7 @@ public:
     virtual OperatorNameId *asOperatorNameId() { return 0; }
     virtual ConversionNameId *asConversionNameId() { return 0; }
     virtual QualifiedNameId *asQualifiedNameId() { return 0; }
+    virtual SelectorNameId *asSelectorNameId() { return 0; }
 
     virtual bool isEqualTo(const Name *other) const = 0;
 
diff --git a/src/shared/cplusplus/NameVisitor.h b/src/shared/cplusplus/NameVisitor.h
index 18921375632..16ba837d645 100644
--- a/src/shared/cplusplus/NameVisitor.h
+++ b/src/shared/cplusplus/NameVisitor.h
@@ -74,6 +74,7 @@ public:
     virtual void visit(OperatorNameId *) {}
     virtual void visit(ConversionNameId *) {}
     virtual void visit(QualifiedNameId *) {}
+    virtual void visit(SelectorNameId *) {}
 };
 
 CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Names.cpp b/src/shared/cplusplus/Names.cpp
index 3dafad910b2..32762841b6f 100644
--- a/src/shared/cplusplus/Names.cpp
+++ b/src/shared/cplusplus/Names.cpp
@@ -268,5 +268,62 @@ bool ConversionNameId::isEqualTo(const Name *other) const
     return _type.isEqualTo(c->type());
 }
 
+SelectorNameId::SelectorNameId(Name *const names[],
+                               unsigned nameCount,
+                               bool hasArguments)
+    : _names(0),
+      _nameCount(nameCount),
+      _hasArguments(hasArguments)
+{
+    if (_nameCount) {
+        _names = new Name *[_nameCount];
+        std::copy(&names[0], &names[nameCount], _names);
+    }
+}
+
+SelectorNameId::~SelectorNameId()
+{ delete[] _names; }
+
+void SelectorNameId::accept0(NameVisitor *visitor)
+{ visitor->visit(this); }
+
+Identifier *SelectorNameId::identifier() const
+{
+    // FIXME: (EV)
+    return nameAt(0)->identifier();
+}
+
+unsigned SelectorNameId::nameCount() const
+{ return _nameCount; }
+
+Name *SelectorNameId::nameAt(unsigned index) const
+{ return _names[index]; }
+
+Name *const *SelectorNameId::names() const
+{ return _names; }
+
+bool SelectorNameId::hasArguments() const
+{ return _hasArguments; }
+
+bool SelectorNameId::isEqualTo(const Name *other) const
+{
+    const SelectorNameId *q = other->asSelectorNameId();
+    if (! q)
+        return false;
+    else if (hasArguments() != q->hasArguments())
+        return false;
+    else {
+        const unsigned count = nameCount();
+        if (count != q->nameCount())
+            return false;
+        for (unsigned i = 0; i < count; ++i) {
+            Name *l = nameAt(i);
+            Name *r = q->nameAt(i);
+            if (! l->isEqualTo(r))
+                return false;
+        }
+    }
+    return true;
+}
 
 CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Names.h b/src/shared/cplusplus/Names.h
index c5758ba7384..b0dc3956301 100644
--- a/src/shared/cplusplus/Names.h
+++ b/src/shared/cplusplus/Names.h
@@ -271,6 +271,39 @@ private:
     FullySpecifiedType _type;
 };
 
+class CPLUSPLUS_EXPORT SelectorNameId: public Name
+{
+public:
+    SelectorNameId(Name *const names[],
+                   unsigned nameCount,
+                   bool hasArguments);
+    virtual ~SelectorNameId();
+
+    virtual Identifier *identifier() const;
+
+    unsigned nameCount() const;
+    Name *nameAt(unsigned index) const;
+    Name *const *names() const;
+
+    bool hasArguments() const;
+
+    virtual bool isEqualTo(const Name *other) const;
+
+    virtual const SelectorNameId *asSelectorNameId() const
+    { return this; }
+
+    virtual SelectorNameId *asSelectorNameId()
+    { return this; }
+
+protected:
+    virtual void accept0(NameVisitor *visitor);
+
+private:
+    Name **_names;
+    unsigned _nameCount;
+    bool _hasArguments;
+};
+
 CPLUSPLUS_END_NAMESPACE
 CPLUSPLUS_END_HEADER
 
diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp
index d0a7b05bcbe..ee8e714f64e 100644
--- a/src/shared/cplusplus/Parser.cpp
+++ b/src/shared/cplusplus/Parser.cpp
@@ -2967,7 +2967,7 @@ bool Parser::parseObjCMessageExpression(ExpressionAST *&node)
     ast->lbracket_token = consumeToken();
 
     parseObjCMessageReceiver(ast->receiver_expression);
-    parseObjCMessageArguments(ast->argument_list);
+    parseObjCMessageArguments(ast->selector, ast->argument_list);
 
     match(T_RBRACKET, &(ast->rbracket_token));
     node = ast;
@@ -2979,25 +2979,34 @@ bool Parser::parseObjCMessageReceiver(ExpressionAST *&node)
     return parseExpression(node);
 }
 
-bool Parser::parseObjCMessageArguments(ObjCMessageArgumentListAST *& node)
+bool Parser::parseObjCMessageArguments(ObjCSelectorAST *&selNode, ObjCMessageArgumentListAST *& argNode)
 {
     if (LA() == T_RBRACKET)
         return false; // nothing to do.
 
     unsigned start = cursor();
 
-    ObjCMessageArgumentListAST *ast = new (_pool) ObjCMessageArgumentListAST;
-    ObjCMessageArgumentAST *argument = 0;
+    ObjCSelectorArgumentAST *selectorArgument = 0;
+    ObjCMessageArgumentAST *messageArgument = 0;
 
-    if (parseObjCSelectorArg(argument)) {
-        ast->arg = argument;
-        ObjCMessageArgumentListAST *lastArgument = ast;
+    if (parseObjCSelectorArg(selectorArgument, messageArgument)) {
+        ObjCSelectorArgumentListAST *selAst = new (_pool) ObjCSelectorArgumentListAST;
+        selAst->argument = selectorArgument;
+        ObjCSelectorArgumentListAST *lastSelector = selAst;
 
-        while (parseObjCSelectorArg(argument)) {
+        ObjCMessageArgumentListAST *argAst = new (_pool) ObjCMessageArgumentListAST;
+        argAst->arg = messageArgument;
+        ObjCMessageArgumentListAST *lastArgument = argAst;
+
+        while (parseObjCSelectorArg(selectorArgument, messageArgument)) {
             // accept the selector args.
+            lastSelector->next = new (_pool) ObjCSelectorArgumentListAST;
+            lastSelector = lastSelector->next;
+            lastSelector->argument = selectorArgument;
+
             lastArgument->next = new (_pool) ObjCMessageArgumentListAST;
             lastArgument = lastArgument->next;
-            lastArgument->arg = argument;
+            lastArgument->arg = messageArgument;
         }
 
         if (LA() == T_COMMA) {
@@ -3011,17 +3020,24 @@ bool Parser::parseObjCMessageArguments(ObjCMessageArgumentListAST *& node)
                 lastExpression = &(binaryExpression->right_expression);
             }
         }
+
+        ObjCSelectorWithArgumentsAST *selWithArgs = new (_pool) ObjCSelectorWithArgumentsAST;
+        selWithArgs->selector_arguments = selAst;
+
+        selNode = selWithArgs;
+        argNode = argAst;
     } else {
         rewind(start);
-        ast->arg = new (_pool) ObjCMessageArgumentAST;
-        parseObjCSelector(ast->arg->parameter_key_identifier);
+        ObjCSelectorWithoutArgumentsAST *sel = new (_pool) ObjCSelectorWithoutArgumentsAST;
+        parseObjCSelector(sel->name_token);
+        selNode = sel;
+        argNode = 0;
     }
 
-    node = ast;
     return true;
 }
 
-bool Parser::parseObjCSelectorArg(ObjCMessageArgumentAST *&node)
+bool Parser::parseObjCSelectorArg(ObjCSelectorArgumentAST *&selNode, ObjCMessageArgumentAST *&argNode)
 {
     unsigned selector_token = 0;
     if (!parseObjCSelector(selector_token))
@@ -3030,12 +3046,12 @@ bool Parser::parseObjCSelectorArg(ObjCMessageArgumentAST *&node)
     if (LA() != T_COLON)
         return false;
 
-    ObjCMessageArgumentAST *argument = new (_pool) ObjCMessageArgumentAST;
-    argument->parameter_key_identifier = selector_token;
-    argument->colon_token = consumeToken();
+    selNode = new (_pool) ObjCSelectorArgumentAST;
+    selNode->name_token = selector_token;
+    selNode->colon_token = consumeToken();
 
-    parseAssignmentExpression(argument->parameter_value_expression);
-    node = argument;
+    argNode = new (_pool) ObjCMessageArgumentAST;
+    parseAssignmentExpression(argNode->parameter_value_expression);
     return true;
 }
 
diff --git a/src/shared/cplusplus/Parser.h b/src/shared/cplusplus/Parser.h
index ec40707613d..181e4b6b712 100644
--- a/src/shared/cplusplus/Parser.h
+++ b/src/shared/cplusplus/Parser.h
@@ -226,8 +226,8 @@ public:
     bool parseObjCMethodSignature();
     bool parseObjCMessageExpression(ExpressionAST *&node);
     bool parseObjCMessageReceiver(ExpressionAST *&node);
-    bool parseObjCMessageArguments(ObjCMessageArgumentListAST *&node);
-    bool parseObjCSelectorArg(ObjCMessageArgumentAST *&node);
+    bool parseObjCMessageArguments(ObjCSelectorAST *&selNode, ObjCMessageArgumentListAST *& argNode);
+    bool parseObjCSelectorArg(ObjCSelectorArgumentAST *&selNode, ObjCMessageArgumentAST *&argNode);
     bool parseObjCMethodDefinitionList(DeclarationListAST *&node);
     bool parseObjCMethodDefinition(DeclarationAST *&node);
 
-- 
GitLab