diff --git a/src/libs/cplusplus/CheckUndefinedSymbols.cpp b/src/libs/cplusplus/CheckUndefinedSymbols.cpp
index ca43b1fb3d90fb01f2aa82e790f3c3d3594c2429..5f0b6b2d27df826c8d5e9fb8f9646b34de32e6fb 100644
--- a/src/libs/cplusplus/CheckUndefinedSymbols.cpp
+++ b/src/libs/cplusplus/CheckUndefinedSymbols.cpp
@@ -51,6 +51,7 @@ void CheckUndefinedSymbols::setGlobalNamespaceBinding(NamespaceBindingPtr global
 {
     _globalNamespaceBinding = globalNamespaceBinding;
     _types.clear();
+    _protocols.clear();
 
     if (_globalNamespaceBinding) {
         QSet<NamespaceBinding *> processed;
@@ -130,23 +131,43 @@ void CheckUndefinedSymbols::addType(Name *name)
         _types.insert(QByteArray(id->chars(), id->size()));
 }
 
+void CheckUndefinedSymbols::addProtocol(Name *name)
+{
+    if (!name)
+        return;
+
+    if (Identifier *id = name->identifier())
+        _protocols.insert(QByteArray(id->chars(), id->size()));
+}
+
+bool CheckUndefinedSymbols::isProtocol(const QByteArray &name) const
+{
+    return _protocols.contains(name);
+}
+
 void CheckUndefinedSymbols::buildTypeMap(Class *klass)
 {
     addType(klass->name());
 
     for (unsigned i = 0; i < klass->memberCount(); ++i) {
-        Symbol *member = klass->memberAt(i);
-
-        if (Class *klass = member->asClass()) {
-            buildTypeMap(klass);
-        } else if (Enum *e = member->asEnum()) {
-            addType(e->name());
-        } else if (ForwardClassDeclaration *fwd = member->asForwardClassDeclaration()) {
-            addType(fwd->name());
-        } else if (Declaration *decl = member->asDeclaration()) {
-            if (decl->isTypedef())
-                addType(decl->name());
-        }
+        buildMemberTypeMap(klass->memberAt(i));
+    }
+}
+
+void CheckUndefinedSymbols::buildMemberTypeMap(Symbol *member)
+{
+    if (member == 0)
+        return;
+
+    if (Class *klass = member->asClass()) {
+        buildTypeMap(klass);
+    } else if (Enum *e = member->asEnum()) {
+        addType(e->name());
+    } else if (ForwardClassDeclaration *fwd = member->asForwardClassDeclaration()) {
+        addType(fwd->name());
+    } else if (Declaration *decl = member->asDeclaration()) {
+        if (decl->isTypedef())
+            addType(decl->name());
     }
 }
 
@@ -176,10 +197,16 @@ void CheckUndefinedSymbols::buildTypeMap(NamespaceBinding *binding, QSet<Namespa
                     addType(fKlass->name());
                 } else if (ObjCClass *klass = member->asObjCClass()) {
                     addType(klass->name());
+
+                    for (unsigned i = 0; i < klass->memberCount(); ++i)
+                        buildMemberTypeMap(klass->memberAt(i));
                 } else if (ObjCForwardProtocolDeclaration *fProto = member->asObjCForwardProtocolDeclaration()) {
-                    addType(fProto->name());
+                    addProtocol(fProto->name());
                 } else if (ObjCProtocol *proto = member->asObjCProtocol()) {
-                    addType(proto->name());
+                    addProtocol(proto->name());
+
+                    for (unsigned i = 0; i < proto->memberCount(); ++i)
+                        buildMemberTypeMap(proto->memberAt(i));
                 }
             }
         }
@@ -454,3 +481,53 @@ bool CheckUndefinedSymbols::visit(SizeofExpressionAST *ast)
 
     return true;
 }
+
+bool CheckUndefinedSymbols::visit(ObjCClassDeclarationAST *ast)
+{
+    if (NameAST *nameAST = ast->superclass) {
+        bool resolvedSuperClassName = false;
+
+        if (Name *name = nameAST->name) {
+            Identifier *id = name->identifier();
+            const QByteArray spell = QByteArray::fromRawData(id->chars(), id->size());
+            if (isType(spell))
+                resolvedSuperClassName = true;
+        }
+
+        if (! resolvedSuperClassName) {
+            translationUnit()->warning(nameAST->firstToken(),
+                                       "expected class-name after ':' token");
+        }
+    }
+
+    return true;
+}
+
+bool CheckUndefinedSymbols::visit(ObjCProtocolRefsAST *ast)
+{
+    for (IdentifierListAST *iter = ast->identifier_list; iter; iter = iter->next) {
+        if (NameAST *nameAST = iter->name) {
+            bool resolvedProtocolName = false;
+
+            if (Name *name = nameAST->name) {
+                Identifier *id = name->identifier();
+                const QByteArray spell = QByteArray::fromRawData(id->chars(), id->size());
+                if (isProtocol(spell))
+                    resolvedProtocolName = true;
+            }
+
+            if (!resolvedProtocolName) {
+                char after;
+
+                if (iter == ast->identifier_list)
+                    after = '<';
+                else
+                    after = ',';
+
+                translationUnit()->warning(nameAST->firstToken(), "expected protocol name after '%c' token", after);
+            }
+        }
+    }
+
+    return false;
+}
diff --git a/src/libs/cplusplus/CheckUndefinedSymbols.h b/src/libs/cplusplus/CheckUndefinedSymbols.h
index 3108cda0e6f921dec63743db0c6453444d6e05e6..fbdca0f94ec9d2c1fdc7629d8fc0516b693bde3b 100644
--- a/src/libs/cplusplus/CheckUndefinedSymbols.h
+++ b/src/libs/cplusplus/CheckUndefinedSymbols.h
@@ -57,7 +57,10 @@ protected:
 
     void addType(Name *name);
     void buildTypeMap(Class *klass);
+    void buildMemberTypeMap(Symbol *member);
     void buildTypeMap(NamespaceBinding *binding, QSet<NamespaceBinding *> *processed);
+    void addProtocol(Name *name);
+    bool isProtocol(const QByteArray &name) const;
 
     FunctionDeclaratorAST *currentFunctionDeclarator() const;
     CompoundStatementAST *compoundStatement() const;
@@ -91,6 +94,9 @@ protected:
     virtual bool visit(CastExpressionAST *ast);
     virtual bool visit(SizeofExpressionAST *ast);
 
+    virtual bool visit(ObjCClassDeclarationAST *ast);
+    virtual bool visit(ObjCProtocolRefsAST *ast);
+
 private:
     Document::Ptr _doc;
     NamespaceBindingPtr _globalNamespaceBinding;
@@ -99,6 +105,7 @@ private:
     QList<TemplateDeclarationAST *> _templateDeclarationStack;
     QList<CompoundStatementAST *> _compoundStatementStack;
     QSet<QByteArray> _types;
+    QSet<QByteArray> _protocols;
     QSet<QByteArray> _namespaceNames;
 };
 
diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp
index cd0c8f705ed0c204675f699a9ac427b7270dd96e..4216acac8ae2501fc92029fe916be2267885f864 100644
--- a/src/plugins/cpptools/cppcodecompletion.cpp
+++ b/src/plugins/cpptools/cppcodecompletion.cpp
@@ -161,7 +161,7 @@ public:
         Symbol *previousSymbol = switchSymbol(symbol);
         accept(symbol->identity());
         if (_item)
-            _item.m_data = QVariant::fromValue(symbol);
+            _item.data = QVariant::fromValue(symbol);
         (void) switchSymbol(previousSymbol);
         return switchCompletionItem(previousItem);
     }
@@ -184,8 +184,8 @@ protected:
     TextEditor::CompletionItem newCompletionItem(Name *name)
     {
         TextEditor::CompletionItem item(_collector);
-        item.m_text = overview.prettyName(name);
-        item.m_icon = _collector->iconForSymbol(_symbol);
+        item.text = overview.prettyName(name);
+        item.icon = _collector->iconForSymbol(_symbol);
         return item;
     }
 
@@ -195,7 +195,7 @@ protected:
     virtual void visit(TemplateNameId *name)
     {
         _item = newCompletionItem(name);
-        _item.m_text = QLatin1String(name->identifier()->chars());
+        _item.text = QLatin1String(name->identifier()->chars());
     }
 
     virtual void visit(DestructorNameId *name)
@@ -474,8 +474,8 @@ int CppQuickFixCollector::startCompletion(TextEditor::ITextEditable *editor)
             int i = 0;
             foreach (QuickFixOperationPtr op, quickFixes) {
                 TextEditor::CompletionItem item(this);
-                item.m_text = op->description();
-                item.m_data = QVariant::fromValue(i);
+                item.text = op->description();
+                item.data = QVariant::fromValue(i);
                 _completions.append(item);
                 ++i;
             }
@@ -494,7 +494,7 @@ void CppQuickFixCollector::complete(const TextEditor::CompletionItem &item)
 {
     CppEditorSupport *extra = _modelManager->editorSupport(_editor);
     const QList<QuickFixOperationPtr> quickFixes = extra->quickFixes();
-    QuickFixOperationPtr quickFix = quickFixes.at(item.m_data.toInt());
+    QuickFixOperationPtr quickFix = quickFixes.at(item.data.toInt());
     TextEditor::BaseTextEditor *ed = qobject_cast<TextEditor::BaseTextEditor *>(_editor->widget());
     quickFix->apply(ed->textCursor());
 }
@@ -508,7 +508,7 @@ CppCodeCompletion::CppCodeCompletion(CppModelManager *manager)
     : ICompletionCollector(manager),
       m_manager(manager),
       m_caseSensitivity(Qt::CaseSensitive),
-      m_autoInsertBrackets(true),
+      awesome(true),
       m_forcedCompletion(false),
       m_completionOperator(T_EOF_SYMBOL)
 {
@@ -531,12 +531,12 @@ void CppCodeCompletion::setCaseSensitivity(Qt::CaseSensitivity caseSensitivity)
 
 bool CppCodeCompletion::autoInsertBrackets() const
 {
-    return m_autoInsertBrackets;
+    return awesome;
 }
 
 void CppCodeCompletion::setAutoInsertBrackets(bool autoInsertBrackets)
 {
-    m_autoInsertBrackets = autoInsertBrackets;
+    awesome = autoInsertBrackets;
 }
 
 bool CppCodeCompletion::isPartialCompletionEnabled() const
@@ -757,8 +757,8 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
     if (m_completionOperator == T_DOXY_COMMENT) {
         for (int i = 1; i < T_DOXY_LAST_TAG; ++i) {
             TextEditor::CompletionItem item(this);
-            item.m_text.append(QString::fromLatin1(doxygenTagSpell(i)));
-            item.m_icon = m_icons.keywordIcon();
+            item.text.append(QString::fromLatin1(doxygenTagSpell(i)));
+            item.icon = m_icons.keywordIcon();
             m_completions.append(item);
         }
 
@@ -1148,8 +1148,8 @@ void CppCodeCompletion::addKeywords()
     // keyword completion items.
     for (int i = T_FIRST_KEYWORD; i < T_FIRST_OBJC_AT_KEYWORD; ++i) {
         TextEditor::CompletionItem item(this);
-        item.m_text = QLatin1String(Token::name(i));
-        item.m_icon = m_icons.keywordIcon();
+        item.text = QLatin1String(Token::name(i));
+        item.icon = m_icons.keywordIcon();
         m_completions.append(item);
     }
 }
@@ -1164,8 +1164,8 @@ void CppCodeCompletion::addMacros(const LookupContext &context)
 
     foreach (const QString &macroName, definedMacros) {
         TextEditor::CompletionItem item(this);
-        item.m_text = macroName;
-        item.m_icon = m_icons.macroIcon();
+        item.text = macroName;
+        item.icon = m_icons.macroIcon();
         m_completions.append(item);
     }
 }
@@ -1235,9 +1235,9 @@ bool CppCodeCompletion::completeInclude(const QTextCursor &cursor)
             }
             foreach (const QString &itemText, m_manager->includesInPath(realPath)) {
                 TextEditor::CompletionItem item(this);
-                item.m_text += itemText;
+                item.text += itemText;
                 // TODO: Icon for include files
-                item.m_icon = m_icons.keywordIcon();
+                item.icon = m_icons.keywordIcon();
                 m_completions.append(item);
             }
         }
@@ -1252,9 +1252,9 @@ bool CppCodeCompletion::completeInclude(const QTextCursor &cursor)
             }
             foreach (const QString &itemText, m_manager->includesInPath(realPath)) {
                 TextEditor::CompletionItem item(this);
-                item.m_text += itemText;
+                item.text += itemText;
                 // TODO: Icon for include files
-                item.m_icon = m_icons.keywordIcon();
+                item.icon = m_icons.keywordIcon();
                 m_completions.append(item);
             }
         }
@@ -1389,7 +1389,7 @@ bool CppCodeCompletion::completeQtMethod(const QList<TypeOfExpression::Result> &
                         if (! signatures.contains(signature)) {
                             signatures.insert(signature);
 
-                            ci.m_text = signature; // fix the completion item.
+                            ci.text = signature; // fix the completion item.
                             m_completions.append(ci);
                         }
 
@@ -1446,9 +1446,9 @@ void CppCodeCompletion::completions(QList<TextEditor::CompletionItem> *completio
             const QRegExp regExp(keyRegExp, m_caseSensitivity);
 
             foreach (TextEditor::CompletionItem item, m_completions) {
-                if (regExp.indexIn(item.m_text) == 0) {
-                    item.m_relevance = (key.length() > 0 &&
-                                         item.m_text.startsWith(key, Qt::CaseInsensitive)) ? 1 : 0;
+                if (regExp.indexIn(item.text) == 0) {
+                    item.relevance = (key.length() > 0 &&
+                                         item.text.startsWith(key, Qt::CaseInsensitive)) ? 1 : 0;
                     (*completions) << item;
                 }
             }
@@ -1456,7 +1456,7 @@ void CppCodeCompletion::completions(QList<TextEditor::CompletionItem> *completio
                    m_completionOperator == T_SIGNAL ||
                    m_completionOperator == T_SLOT) {
             foreach (TextEditor::CompletionItem item, m_completions) {
-                if (item.m_text.startsWith(key, Qt::CaseInsensitive)) {
+                if (item.text.startsWith(key, Qt::CaseInsensitive)) {
                     (*completions) << item;
                 }
             }
@@ -1468,8 +1468,8 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
 {
     Symbol *symbol = 0;
 
-    if (item.m_data.isValid())
-        symbol = item.m_data.value<Symbol *>();
+    if (item.data.isValid())
+        symbol = item.data.value<Symbol *>();
 
     QString toInsert;
     QString extraChars;
@@ -1479,19 +1479,19 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
     bool autoParenthesesEnabled = true;
 
     if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
-        toInsert = item.m_text;
+        toInsert = item.text;
         extraChars += QLatin1Char(')');
     } else if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL) {
-        toInsert = item.m_text;
+        toInsert = item.text;
         if (!toInsert.endsWith(QLatin1Char('/')))
             extraChars += QLatin1Char((m_completionOperator == T_ANGLE_STRING_LITERAL) ? '>' : '"');
     } else {
-        toInsert = item.m_text;
+        toInsert = item.text;
 
         //qDebug() << "current symbol:" << overview.prettyName(symbol->name())
         //<< overview.prettyType(symbol->type());
 
-        if (m_autoInsertBrackets && symbol && symbol->type()) {
+        if (awesome && symbol && symbol->type()) {
             if (Function *function = symbol->type()->asFunctionType()) {
                 // If the member is a function, automatically place the opening parenthesis,
                 // except when it might take template parameters.
@@ -1511,7 +1511,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
                     bool endWithSemicolon = function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON;
 
                     // If the function takes no arguments, automatically place the closing parenthesis
-                    if (item.m_duplicateCount == 0 && ! function->hasArguments()) {
+                    if (item.duplicateCount == 0 && ! function->hasArguments()) {
                         extraChars += QLatin1Char(')');
                         if (endWithSemicolon)
                             extraChars += QLatin1Char(';');
@@ -1560,8 +1560,8 @@ bool CppCodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem
         return true;
     } else if (m_partialCompletionEnabled && m_completionOperator != T_LPAREN) {
         // Compute common prefix
-        QString firstKey = completionItems.first().m_text;
-        QString lastKey = completionItems.last().m_text;
+        QString firstKey = completionItems.first().text;
+        QString lastKey = completionItems.last().text;
         const int length = qMin(firstKey.length(), lastKey.length());
         firstKey.truncate(length);
         lastKey.truncate(length);
diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h
index afe8a1682153219f006b6f7742e2397aad506445..484b6425bcb2c884cb0b03b318de037785f289d9 100644
--- a/src/plugins/cpptools/cppcodecompletion.h
+++ b/src/plugins/cpptools/cppcodecompletion.h
@@ -151,7 +151,7 @@ private:
 
     CppModelManager *m_manager;
     Qt::CaseSensitivity m_caseSensitivity;
-    bool m_autoInsertBrackets;
+    bool awesome;
     bool m_partialCompletionEnabled;
 
     bool m_forcedCompletion;
diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp
index f9c27ccdd94ba196933ec9dedcaf0f7297da1b12..95e1b8273dfd78eb60681fde5a5a6539786a8256 100644
--- a/src/plugins/cpptools/cppfindreferences.cpp
+++ b/src/plugins/cpptools/cppfindreferences.cpp
@@ -534,17 +534,24 @@ static void find_helper(QFutureInterface<Utils::FileSearchResult> &future,
 
 void CppFindReferences::findUsages(Symbol *symbol)
 {
-    _resultWindow->clearContents();
+    Find::SearchResult *search = _resultWindow->startNewSearch(Find::SearchResultWindow::SearchOnly);
+
+    connect(search, SIGNAL(activated(Find::SearchResultItem)),
+            this, SLOT(openEditor(Find::SearchResultItem)));
+
     findAll_helper(symbol);
 }
 
 void CppFindReferences::renameUsages(Symbol *symbol)
 {
-    Find::SearchResult *search = _resultWindow->startNewSearch();
+    Find::SearchResult *search = _resultWindow->startNewSearch(Find::SearchResultWindow::SearchAndReplace);
+
     connect(search, SIGNAL(activated(Find::SearchResultItem)),
             this, SLOT(openEditor(Find::SearchResultItem)));
 
-    _resultWindow->setShowReplaceUI(true);
+    connect(search, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)),
+            SLOT(onReplaceButtonClicked(QString,QList<Find::SearchResultItem>)));
+
     findAll_helper(symbol);
 }
 
@@ -567,6 +574,60 @@ void CppFindReferences::findAll_helper(Symbol *symbol)
     connect(progress, SIGNAL(clicked()), _resultWindow, SLOT(popup()));
 }
 
+void CppFindReferences::onReplaceButtonClicked(const QString &text,
+                                               const QList<Find::SearchResultItem> &items)
+{
+    if (text.isEmpty())
+        return;
+
+    QHash<QString, QList<Find::SearchResultItem> > changes;
+
+    foreach (const Find::SearchResultItem &item, items)
+        changes[item.fileName].append(item);
+
+    QHashIterator<QString, QList<Find::SearchResultItem> > it(changes);
+    while (it.hasNext()) {
+        it.next();
+
+        const QString fileName = it.key();
+        QFile file(fileName);
+
+        if (file.open(QFile::ReadOnly)) {
+            QTextStream stream(&file);
+            // ### set the encoding
+            const QString plainText = stream.readAll();
+            file.close();
+
+            QTextDocument doc;
+            doc.setPlainText(plainText);
+
+            QList<QTextCursor> cursors;
+            const QList<Find::SearchResultItem> items = it.value();
+            foreach (const Find::SearchResultItem &item, items) {
+                const int blockNumber = item.lineNumber - 1;
+                QTextCursor tc(doc.findBlockByNumber(blockNumber));
+                tc.setPosition(tc.position() + item.searchTermStart);
+                tc.setPosition(tc.position() + item.searchTermLength,
+                               QTextCursor::KeepAnchor);
+                cursors.append(tc);
+            }
+
+            foreach (QTextCursor tc, cursors)
+                tc.insertText(text);
+
+            QFile newFile(fileName);
+            if (newFile.open(QFile::WriteOnly)) {
+                QTextStream stream(&newFile);
+                // ### set the encoding
+                stream << doc.toPlainText();
+            }
+        }
+    }
+
+    const QStringList fileNames = changes.keys();
+    _modelManager->updateSourceFiles(fileNames);
+}
+
 void CppFindReferences::displayResult(int index)
 {
     Utils::FileSearchResult result = m_watcher.future().resultAt(index);
diff --git a/src/plugins/cpptools/cppfindreferences.h b/src/plugins/cpptools/cppfindreferences.h
index 429a945e2c8c476dd816eb780d1ad50ae77c7d05..4b4a5a9b04b86db4987c94edfb02c0f0f624219f 100644
--- a/src/plugins/cpptools/cppfindreferences.h
+++ b/src/plugins/cpptools/cppfindreferences.h
@@ -70,6 +70,7 @@ private Q_SLOTS:
     void displayResult(int);
     void searchFinished();
     void openEditor(const Find::SearchResultItem &item);
+    void onReplaceButtonClicked(const QString &text, const QList<Find::SearchResultItem> &items);
 
 private:
     void findAll_helper(CPlusPlus::Symbol *symbol);
diff --git a/src/plugins/find/searchresultwindow.cpp b/src/plugins/find/searchresultwindow.cpp
index f9b6caf3cf9225cb1a8f570447743e4926e92a35..2f846cd89c88f95328b25ff00fbb992114df8941 100644
--- a/src/plugins/find/searchresultwindow.cpp
+++ b/src/plugins/find/searchresultwindow.cpp
@@ -87,6 +87,7 @@ SearchResultWindow::SearchResultWindow()
     connect(m_searchResultTreeView, SIGNAL(jumpToSearchResult(int,bool)),
             this, SLOT(handleJumpToSearchResult(int,bool)));
     connect(m_expandCollapseToolButton, SIGNAL(toggled(bool)), this, SLOT(handleExpandCollapseToolButton(bool)));
+    connect(m_replaceTextEdit, SIGNAL(returnPressed()), this, SLOT(handleReplaceButton()));
     connect(m_replaceButton, SIGNAL(clicked()), this, SLOT(handleReplaceButton()));
 
     readSettings();
diff --git a/src/plugins/qmleditor/qmlcodecompletion.cpp b/src/plugins/qmleditor/qmlcodecompletion.cpp
index 5f51916e4c9d2ca7828496a433c88a55cef8181c..c0b69213d3ad217e48305fbebd730c779e5c8eed 100644
--- a/src/plugins/qmleditor/qmlcodecompletion.cpp
+++ b/src/plugins/qmleditor/qmlcodecompletion.cpp
@@ -52,13 +52,13 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
 
     foreach (const QString &word, edit->keywords()) {
         TextEditor::CompletionItem item(this);
-        item.m_text = word;
+        item.text = word;
         m_completions.append(item);
     }
 
     foreach (const QString &word, edit->words()) {
         TextEditor::CompletionItem item(this);
-        item.m_text = word;
+        item.text = word;
         m_completions.append(item);
     }
 
@@ -71,7 +71,7 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
 
             foreach (const QString &word, visitor(program, m_startPosition)) {
                 TextEditor::CompletionItem item(this);
-                item.m_text = word;
+                item.text = word;
                 m_completions.append(item);
             }
         }
@@ -120,9 +120,9 @@ void QmlCodeCompletion::completions(QList<TextEditor::CompletionItem> *completio
         const QRegExp regExp(keyRegExp, Qt::CaseSensitive);
 
         foreach (TextEditor::CompletionItem item, m_completions) {
-            if (regExp.indexIn(item.m_text) == 0) {
-                item.m_relevance = (key.length() > 0 &&
-                                    item.m_text.startsWith(key, Qt::CaseInsensitive)) ? 1 : 0;
+            if (regExp.indexIn(item.text) == 0) {
+                item.relevance = (key.length() > 0 &&
+                                    item.text.startsWith(key, Qt::CaseInsensitive)) ? 1 : 0;
                 (*completions) << item;
             }
         }
@@ -131,7 +131,7 @@ void QmlCodeCompletion::completions(QList<TextEditor::CompletionItem> *completio
 
 void QmlCodeCompletion::complete(const TextEditor::CompletionItem &item)
 {
-    const QString toInsert = item.m_text;
+    const QString toInsert = item.text;
     const int length = m_editor->position() - m_startPosition;
     m_editor->setCurPos(m_startPosition);
     m_editor->replace(length, toInsert);
@@ -144,8 +144,8 @@ bool QmlCodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem
         return true;
     } else {
         // Compute common prefix
-        QString firstKey = completionItems.first().m_text;
-        QString lastKey = completionItems.last().m_text;
+        QString firstKey = completionItems.first().text;
+        QString lastKey = completionItems.last().text;
         const int length = qMin(firstKey.length(), lastKey.length());
         firstKey.truncate(length);
         lastKey.truncate(length);
diff --git a/src/plugins/qtscripteditor/qtscriptcodecompletion.cpp b/src/plugins/qtscripteditor/qtscriptcodecompletion.cpp
index 3bd0071993478ea6b45c9100b22d510ebaf986ce..dd1380dceb47b4a09558d7b1aa49e81e903591d0 100644
--- a/src/plugins/qtscripteditor/qtscriptcodecompletion.cpp
+++ b/src/plugins/qtscripteditor/qtscriptcodecompletion.cpp
@@ -55,7 +55,7 @@ int QtScriptCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
 
     foreach (const QString &word, edit->words()) {
         TextEditor::CompletionItem item(this);
-        item.m_text = word;
+        item.text = word;
         m_completions.append(item);
     }
 
@@ -102,9 +102,9 @@ void QtScriptCodeCompletion::completions(QList<TextEditor::CompletionItem> *comp
         const QRegExp regExp(keyRegExp, Qt::CaseSensitive);
 
         foreach (TextEditor::CompletionItem item, m_completions) {
-            if (regExp.indexIn(item.m_text) == 0) {
-                item.m_relevance = (key.length() > 0 &&
-                                    item.m_text.startsWith(key, Qt::CaseInsensitive)) ? 1 : 0;
+            if (regExp.indexIn(item.text) == 0) {
+                item.relevance = (key.length() > 0 &&
+                                    item.text.startsWith(key, Qt::CaseInsensitive)) ? 1 : 0;
                 (*completions) << item;
             }
         }
@@ -113,7 +113,7 @@ void QtScriptCodeCompletion::completions(QList<TextEditor::CompletionItem> *comp
 
 void QtScriptCodeCompletion::complete(const TextEditor::CompletionItem &item)
 {
-    const QString toInsert = item.m_text;
+    const QString toInsert = item.text;
     const int length = m_editor->position() - m_startPosition;
     m_editor->setCurPos(m_startPosition);
     m_editor->replace(length, toInsert);
@@ -126,8 +126,8 @@ bool QtScriptCodeCompletion::partiallyComplete(const QList<TextEditor::Completio
         return true;
     } else {
         // Compute common prefix
-        QString firstKey = completionItems.first().m_text;
-        QString lastKey = completionItems.last().m_text;
+        QString firstKey = completionItems.first().text;
+        QString lastKey = completionItems.last().text;
         const int length = qMin(firstKey.length(), lastKey.length());
         firstKey.truncate(length);
         lastKey.truncate(length);
diff --git a/src/plugins/texteditor/completionsupport.cpp b/src/plugins/texteditor/completionsupport.cpp
index 640e8f7bf4e460bcd03c4e71600b3ce0bc241a6c..5657650c46f3ca767ccd58f612f68d2c6dae5516 100644
--- a/src/plugins/texteditor/completionsupport.cpp
+++ b/src/plugins/texteditor/completionsupport.cpp
@@ -67,7 +67,7 @@ CompletionSupport::CompletionSupport()
 
 void CompletionSupport::performCompletion(const CompletionItem &item)
 {
-    item.m_collector->complete(item);
+    item.collector->complete(item);
     m_checkCompletionTrigger = true;
 }
 
@@ -189,10 +189,10 @@ static bool lessThan(const QString &l, const QString &r)
 static bool completionItemLessThan(const CompletionItem &i1, const CompletionItem &i2)
 {
     // The order is case-insensitive in principle, but case-sensitive when this would otherwise mean equality
-    const QString lower1 = i1.m_text.toLower();
-    const QString lower2 = i2.m_text.toLower();
+    const QString lower1 = i1.text.toLower();
+    const QString lower2 = i2.text.toLower();
     if (lower1 == lower2)
-        return lessThan(i1.m_text, i2.m_text);
+        return lessThan(i1.text, i2.text);
     else
         return lessThan(lower1, lower2);
 }
@@ -210,11 +210,11 @@ QList<CompletionItem> CompletionSupport::getCompletions() const
     QList<CompletionItem> uniquelist;
 
     foreach (const CompletionItem &item, completionItems) {
-        if (item.m_text != lastKey) {
+        if (item.text != lastKey) {
             uniquelist.append(item);
-            lastKey = item.m_text;
+            lastKey = item.text;
         } else {
-            uniquelist.last().m_duplicateCount++;
+            uniquelist.last().duplicateCount++;
         }
     }
 
diff --git a/src/plugins/texteditor/completionwidget.cpp b/src/plugins/texteditor/completionwidget.cpp
index c656500f0724e6084f4f835285bb4c6fa4059801..e4f7c97b80e0f5c0e5a9afec88f5f325a12173a4 100644
--- a/src/plugins/texteditor/completionwidget.cpp
+++ b/src/plugins/texteditor/completionwidget.cpp
@@ -87,11 +87,11 @@ QVariant AutoCompletionModel::data(const QModelIndex &index, int role) const
         return QVariant();
 
     if (role == Qt::DisplayRole) {
-        return itemAt(index).m_text;
+        return itemAt(index).text;
     } else if (role == Qt::DecorationRole) {
-        return itemAt(index).m_icon;
+        return itemAt(index).icon;
     } else if (role == Qt::ToolTipRole) {
-        return itemAt(index).m_details;
+        return itemAt(index).details;
     }
 
     return QVariant();
@@ -231,8 +231,8 @@ void CompletionWidget::setCompletionItems(const QList<TextEditor::CompletionItem
     int mostRelevantIndex = 0;
     for (int i = 0; i < completionItems.size(); ++i) {
         const CompletionItem &item = completionItems.at(i);
-        if (item.m_relevance > relevance) {
-            relevance = item.m_relevance;
+        if (item.relevance > relevance) {
+            relevance = item.relevance;
             mostRelevantIndex = i;
         }
     }
diff --git a/src/plugins/texteditor/icompletioncollector.h b/src/plugins/texteditor/icompletioncollector.h
index 18cba3e61985b2866983f800028b98ab28bc6a22..da5373d035fcb13148f71db9a9b22254fb54cf8b 100644
--- a/src/plugins/texteditor/icompletioncollector.h
+++ b/src/plugins/texteditor/icompletioncollector.h
@@ -44,24 +44,24 @@ class ITextEditable;
 struct CompletionItem
 {
     CompletionItem(ICompletionCollector *collector = 0)
-        : m_relevance(0),
-          m_duplicateCount(0),
-          m_collector(collector)
+        : relevance(0),
+          duplicateCount(0),
+          collector(collector)
     { }
 
     bool isValid() const
-    { return m_collector != 0; }
+    { return collector != 0; }
 
     operator bool() const
-    { return m_collector != 0; }
-
-    QString m_text;
-    QString m_details;
-    QIcon m_icon;
-    QVariant m_data;
-    int m_relevance;
-    int m_duplicateCount;
-    ICompletionCollector *m_collector;
+    { return collector != 0; }
+
+    QString text;
+    QString details;
+    QIcon icon;
+    QVariant data;
+    int relevance;
+    int duplicateCount;
+    ICompletionCollector *collector;
 };
 
 /* Defines the interface to completion collectors. A completion collector tells
diff --git a/src/shared/cplusplus/AST.cpp b/src/shared/cplusplus/AST.cpp
index 148cad3b956b67c90d6e0d4af07bb9c4fabfc6e8..21e8a1504c014fe5e27de1fc12d9eacc895c77ec 100644
--- a/src/shared/cplusplus/AST.cpp
+++ b/src/shared/cplusplus/AST.cpp
@@ -2359,6 +2359,8 @@ unsigned ObjCMethodPrototypeAST::lastToken() const
 {
     if (attributes)
         return attributes->lastToken();
+    else if (dot_dot_dot_token)
+        return dot_dot_dot_token + 1;
     else if (arguments)
         return arguments->lastToken();
     else if (type_name)
diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h
index b118a1dd169d7d88a5efbc425fd10f753292e945..4af1971e2ee357522755d2dfcb0e087ad155c068 100644
--- a/src/shared/cplusplus/AST.h
+++ b/src/shared/cplusplus/AST.h
@@ -2994,6 +2994,7 @@ public:
     ObjCTypeNameAST *type_name;
     ObjCSelectorAST *selector;
     ObjCMessageArgumentDeclarationListAST *arguments;
+    unsigned dot_dot_dot_token;
     SpecifierAST *attributes;
 
 public: // annotations
diff --git a/src/shared/cplusplus/CPlusPlusForwardDeclarations.h b/src/shared/cplusplus/CPlusPlusForwardDeclarations.h
index eaa49eb173e06170b4ba3efc1551e35e688f0174..2467d4c56b0479d63e2a0699e71ff478a98a32ae 100644
--- a/src/shared/cplusplus/CPlusPlusForwardDeclarations.h
+++ b/src/shared/cplusplus/CPlusPlusForwardDeclarations.h
@@ -137,6 +137,8 @@ class ForwardClassDeclaration;
 class Token;
 
 // Objective-C symbols
+class ObjCBaseClass;
+class ObjCBaseProtocol;
 class ObjCClass;
 class ObjCForwardClassDeclaration;
 class ObjCProtocol;
diff --git a/src/shared/cplusplus/CheckDeclaration.cpp b/src/shared/cplusplus/CheckDeclaration.cpp
index 69e645b1be981c3f5815fe8b5e5a49ca0d44253f..4b2604de407ef54f7b671f5007c8b00cf1ca6530 100644
--- a/src/shared/cplusplus/CheckDeclaration.cpp
+++ b/src/shared/cplusplus/CheckDeclaration.cpp
@@ -57,6 +57,7 @@
 #include "Control.h"
 #include "Literals.h"
 #include <cassert>
+#include <QtCore/QByteArray>
 
 CPLUSPLUS_BEGIN_NAMESPACE
 
@@ -506,11 +507,25 @@ bool CheckDeclaration::visit(ObjCProtocolDeclarationAST *ast)
     ObjCProtocol *protocol = control()->newObjCProtocol(sourceLocation, protocolName);
     protocol->setStartOffset(tokenAt(ast->firstToken()).offset);
     protocol->setEndOffset(tokenAt(ast->lastToken()).offset);
-    ast->symbol = protocol;
 
+    if (ast->protocol_refs && ast->protocol_refs->identifier_list) {
+        for (IdentifierListAST *iter = ast->protocol_refs->identifier_list; iter; iter = iter->next) {
+            NameAST* name = iter->name;
+            Name *protocolName = semantic()->check(name, _scope);
+            ObjCBaseProtocol *baseProtocol = control()->newObjCBaseProtocol(name->firstToken(), protocolName);
+            protocol->addProtocol(baseProtocol);
+        }
+    }
+
+    int previousObjCVisibility = semantic()->switchObjCVisibility(Function::Public);
+    for (DeclarationListAST *it = ast->member_declarations; it; it = it->next) {
+        semantic()->check(it->declaration, protocol->members());
+    }
+    (void) semantic()->switchObjCVisibility(previousObjCVisibility);
+
+    ast->symbol = protocol;
     _scope->enterSymbol(protocol);
 
-    // TODO EV: walk protocols and method prototypes
     return false;
 }
 
@@ -562,7 +577,21 @@ bool CheckDeclaration::visit(ObjCClassDeclarationAST *ast)
         klass->setCategoryName(categoryName);
     }
 
-    // TODO: super-class, and protocols (EV)
+    if (ast->superclass) {
+        Name *superClassName = semantic()->check(ast->superclass, _scope);
+        ObjCBaseClass *superKlass = control()->newObjCBaseClass(ast->superclass->firstToken(), superClassName);
+        klass->setBaseClass(superKlass);
+    }
+
+    if (ast->protocol_refs && ast->protocol_refs->identifier_list) {
+        for (IdentifierListAST *iter = ast->protocol_refs->identifier_list; iter; iter = iter->next) {
+            NameAST* name = iter->name;
+            Name *protocolName = semantic()->check(name, _scope);
+            ObjCBaseProtocol *baseProtocol = control()->newObjCBaseProtocol(name->firstToken(), protocolName);
+            klass->addProtocol(baseProtocol);
+        }
+    }
+
     _scope->enterSymbol(klass);
 
     int previousObjCVisibility = semantic()->switchObjCVisibility(Function::Protected);
@@ -627,4 +656,86 @@ bool CheckDeclaration::visit(ObjCVisibilityDeclarationAST *ast)
     return false;
 }
 
+enum PropertyAttributes {
+    None = 0,
+    Assign = 1 << 0,
+    Retain = 1 << 1,
+    Copy = 1 << 2,
+    ReadOnly = 1 << 3,
+    ReadWrite = 1 << 4,
+    Getter = 1 << 5,
+    Setter = 1 << 6,
+    NonAtomic = 1 << 7,
+
+    WritabilityMask = ReadOnly | ReadWrite,
+    SetterSemanticsMask = Assign | Retain | Copy,
+};
+
+bool CheckDeclaration::checkPropertyAttribute(ObjCPropertyAttributeAST *attrAst,
+                                              int &flags,
+                                              int attr)
+{
+    if (flags & attr) {
+        translationUnit()->warning(attrAst->attribute_identifier_token,
+                                   "duplicate property attribute \"%s\"",
+                                   spell(attrAst->attribute_identifier_token));
+        return false;
+    } else {
+        flags |= attr;
+        return true;
+    }
+}
+
+bool CheckDeclaration::visit(ObjCPropertyDeclarationAST *ast)
+{
+    int propAttrs = None;
+
+    for (ObjCPropertyAttributeListAST *iter= ast->property_attributes; iter; iter = iter->next) {
+        ObjCPropertyAttributeAST *attrAst = iter->attr;
+        if (!attrAst)
+            continue;
+
+        const char *attrName = spell(attrAst->attribute_identifier_token);
+        if (!qstrcmp("getter", attrName)) {
+            if (checkPropertyAttribute(attrAst, propAttrs, Getter)) {
+                // TODO: find method declaration for getter
+            }
+        } else if (!qstrcmp("setter", attrName)) {
+            if (checkPropertyAttribute(attrAst, propAttrs, Setter)) {
+                // TODO: find method declaration for setter
+            }
+        } else if (!qstrcmp("readwrite", attrName)) {
+            checkPropertyAttribute(attrAst, propAttrs, ReadWrite);
+        } else if (!qstrcmp("readonly", attrName)) {
+            checkPropertyAttribute(attrAst, propAttrs, ReadOnly);
+        } else if (!qstrcmp("assign", attrName)) {
+            checkPropertyAttribute(attrAst, propAttrs, Assign);
+        } else if (!qstrcmp("retain", attrName)) {
+            checkPropertyAttribute(attrAst, propAttrs, Retain);
+        } else if (!qstrcmp("copy", attrName)) {
+            checkPropertyAttribute(attrAst, propAttrs, Copy);
+        } else if (!qstrcmp("nonatomic", attrName)) {
+            checkPropertyAttribute(attrAst, propAttrs, NonAtomic);
+        }
+    }
+
+    if (propAttrs & ReadOnly && propAttrs & ReadWrite)
+        // Should this be an error instead of only a warning?
+        translationUnit()->warning(ast->property_token,
+                                   "property can have at most one attribute \"readonly\" or \"readwrite\" specified");
+    int setterSemAttrs = propAttrs & SetterSemanticsMask;
+    if (setterSemAttrs
+            && setterSemAttrs != Assign
+            && setterSemAttrs != Retain
+            && setterSemAttrs != Copy) {
+        // Should this be an error instead of only a warning?
+        translationUnit()->warning(ast->property_token,
+                                   "property can have at most one attribute \"assign\", \"retain\", or \"copy\" specified");
+    }
+
+    // TODO: Check if the next line is correct (EV)
+    semantic()->check(ast->simple_declaration, _scope);
+    return false;
+}
+
 CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/CheckDeclaration.h b/src/shared/cplusplus/CheckDeclaration.h
index 27869c75ca3147cf34c8643686cd6aee66218afb..93ef59f941fbb4a313c13a8c2f4686cbce8f61c6 100644
--- a/src/shared/cplusplus/CheckDeclaration.h
+++ b/src/shared/cplusplus/CheckDeclaration.h
@@ -97,7 +97,12 @@ protected:
     virtual bool visit(ObjCClassForwardDeclarationAST *ast);
     virtual bool visit(ObjCMethodDeclarationAST *ast);
     virtual bool visit(ObjCVisibilityDeclarationAST *ast);
+    virtual bool visit(ObjCPropertyDeclarationAST *ast);
 
+private:
+    bool checkPropertyAttribute(ObjCPropertyAttributeAST *attrAst,
+                                int &flags,
+                                int attr);
 private:
     DeclarationAST *_declaration;
     Scope *_scope;
diff --git a/src/shared/cplusplus/CheckDeclarator.cpp b/src/shared/cplusplus/CheckDeclarator.cpp
index 5186055bca9b0f160539df659269d0ebd62ed247..5867d6180aa8a254af1f2952c0a13828cf62da12 100644
--- a/src/shared/cplusplus/CheckDeclarator.cpp
+++ b/src/shared/cplusplus/CheckDeclarator.cpp
@@ -265,14 +265,15 @@ bool CheckDeclarator::visit(ObjCMethodPrototypeAST *ast)
     method->setReturnType(returnType);
 
     if (ast->selector && ast->selector->asObjCSelectorWithArguments()) {
-        // TODO: check the parameters (EV)
-        //    fun->setVariadic(...);
         // TODO: add arguments (EV)
         for (ObjCMessageArgumentDeclarationListAST *it = ast->arguments; it; it = it->next) {
             ObjCMessageArgumentDeclarationAST *argDecl = it->argument_declaration;
 
             semantic()->check(argDecl, method->arguments());
         }
+
+        if (ast->dot_dot_dot_token)
+            method->setVariadic(true);
     }
 
     _fullySpecifiedType = FullySpecifiedType(method);
diff --git a/src/shared/cplusplus/CheckName.cpp b/src/shared/cplusplus/CheckName.cpp
index 84d6762cb9c6ef92c617c8d37aca78c1e661c45e..4a3e884a4727f971bf20cd974ea21da741901989 100644
--- a/src/shared/cplusplus/CheckName.cpp
+++ b/src/shared/cplusplus/CheckName.cpp
@@ -394,8 +394,11 @@ bool CheckName::visit(ObjCSelectorWithArgumentsAST *ast)
 
         names.push_back(name);
     }
-    _name = control()->selectorNameId(&names[0], names.size(), true);
-    ast->selector_name = _name;
+
+    if (!names.empty()) {
+        _name = control()->selectorNameId(&names[0], names.size(), true);
+        ast->selector_name = _name;
+    }
 
     return false;
 }
diff --git a/src/shared/cplusplus/CheckSpecifier.cpp b/src/shared/cplusplus/CheckSpecifier.cpp
index 9cbef353775cfebc9dc7d24b106d4928bf08626f..d4de2c55176d6fb570c949e2e31f036d52e5d13a 100644
--- a/src/shared/cplusplus/CheckSpecifier.cpp
+++ b/src/shared/cplusplus/CheckSpecifier.cpp
@@ -416,8 +416,8 @@ bool CheckSpecifier::visit(AttributeSpecifierAST *ast)
 bool CheckSpecifier::visit(ObjCTypeNameAST * /*ast*/)
 {
     // TODO: implement this (EV)
-    _fullySpecifiedType = FullySpecifiedType();
-    return false;
+//    _fullySpecifiedType = FullySpecifiedType();
+    return true;
 }
 
 CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Control.cpp b/src/shared/cplusplus/Control.cpp
index 07e46fd1ae234e1ddf798050cd82cffcff64fc1f..6338d99fd2251d595379ac2a2f4a3e0ae7b31340 100644
--- a/src/shared/cplusplus/Control.cpp
+++ b/src/shared/cplusplus/Control.cpp
@@ -128,6 +128,8 @@ public:
         delete_array_entries(enums);
         delete_array_entries(usingDeclarations);
         delete_array_entries(classForwardDeclarations);
+        delete_array_entries(objcBaseClasses);
+        delete_array_entries(objcBaseProtocols);
         delete_array_entries(objcClasses);
         delete_array_entries(objcProtocols);
         delete_array_entries(objcForwardClassDeclarations);
@@ -348,6 +350,20 @@ public:
         return c;
     }
 
+    ObjCBaseClass *newObjCBaseClass(unsigned sourceLocation, Name *name)
+    {
+        ObjCBaseClass *c = new ObjCBaseClass(translationUnit, sourceLocation, name);
+        objcBaseClasses.push_back(c);
+        return c;
+    }
+
+    ObjCBaseProtocol *newObjCBaseProtocol(unsigned sourceLocation, Name *name)
+    {
+        ObjCBaseProtocol *p = new ObjCBaseProtocol(translationUnit, sourceLocation, name);
+        objcBaseProtocols.push_back(p);
+        return p;
+    }
+
     ObjCClass *newObjCClass(unsigned sourceLocation, Name *name)
     {
         ObjCClass *c = new ObjCClass(translationUnit, sourceLocation, name);
@@ -561,6 +577,8 @@ public:
     std::vector<Enum *> enums;
     std::vector<UsingDeclaration *> usingDeclarations;
     std::vector<ForwardClassDeclaration *> classForwardDeclarations;
+    std::vector<ObjCBaseClass *> objcBaseClasses;
+    std::vector<ObjCBaseProtocol *> objcBaseProtocols;
     std::vector<ObjCClass *> objcClasses;
     std::vector<ObjCProtocol *> objcProtocols;
     std::vector<ObjCForwardClassDeclaration *> objcForwardClassDeclarations;
@@ -740,6 +758,12 @@ ForwardClassDeclaration *Control::newForwardClassDeclaration(unsigned sourceLoca
                                                              Name *name)
 { return d->newForwardClassDeclaration(sourceLocation, name); }
 
+ObjCBaseClass *Control::newObjCBaseClass(unsigned sourceLocation, Name *name)
+{ return d->newObjCBaseClass(sourceLocation, name); }
+
+ObjCBaseProtocol *Control::newObjCBaseProtocol(unsigned sourceLocation, Name *name)
+{ return d->newObjCBaseProtocol(sourceLocation, name); }
+
 ObjCClass *Control::newObjCClass(unsigned sourceLocation, Name *name)
 { return d->newObjCClass(sourceLocation, name); }
 
diff --git a/src/shared/cplusplus/Control.h b/src/shared/cplusplus/Control.h
index 323740b742288d17112679bf91e9874c4f41e4a8..060be182b685c12e924b25bbd1562c40a479aa7b 100644
--- a/src/shared/cplusplus/Control.h
+++ b/src/shared/cplusplus/Control.h
@@ -166,6 +166,9 @@ public:
     /// Creates a new ForwardClassDeclaration symbol.
     ForwardClassDeclaration *newForwardClassDeclaration(unsigned sourceLocation, Name *name = 0);
 
+    ObjCBaseClass *newObjCBaseClass(unsigned sourceLocation, Name *name);
+    ObjCBaseProtocol *newObjCBaseProtocol(unsigned sourceLocation, Name *name);
+
     /// Creates a new Objective-C class symbol.
     ObjCClass *newObjCClass(unsigned sourceLocation, Name *name = 0);
 
diff --git a/src/shared/cplusplus/ObjectiveCTypeQualifiers.cpp b/src/shared/cplusplus/ObjectiveCTypeQualifiers.cpp
index fa2b7d331420422fdbc6e4fec876f04e60b44377..d12d7c322c169a938fad92c9206ac3a16ba2ffc4 100644
--- a/src/shared/cplusplus/ObjectiveCTypeQualifiers.cpp
+++ b/src/shared/cplusplus/ObjectiveCTypeQualifiers.cpp
@@ -51,6 +51,19 @@ static inline int classify3(const char *s) {
   return Token_identifier;
 }
 
+static inline int classify4(const char *s) {
+    if (s[0] == 'c') {
+        if (s[1] == 'o') {
+            if (s[2] == 'p') {
+                if (s[3] == 'y') {
+                    return Token_copy;
+                }
+            }
+        }
+    }
+    return Token_identifier;
+}
+
 static inline int classify5(const char *s) {
   if (s[0] == 'b') {
     if (s[1] == 'y') {
@@ -78,7 +91,20 @@ static inline int classify5(const char *s) {
 }
 
 static inline int classify6(const char *s) {
-  if (s[0] == 'b') {
+  if (s[0] == 'a') {
+      if (s[1] == 's') {
+          if (s[2] == 's') {
+              if (s[3] == 'i') {
+                  if (s[4] == 'g') {
+                      if (s[5] == 'n') {
+                          return Token_assign;
+                      }
+                  }
+              }
+          }
+      }
+  }
+  else if (s[0] == 'b') {
     if (s[1] == 'y') {
       if (s[2] == 'c') {
         if (s[3] == 'o') {
@@ -91,6 +117,32 @@ static inline int classify6(const char *s) {
       }
     }
   }
+  else if (s[0] == 'g') {
+      if (s[1] == 'e') {
+          if (s[2] == 't') {
+              if (s[3] == 't') {
+                  if (s[4] == 'e') {
+                      if (s[5] == 'r') {
+                          return Token_getter;
+                      }
+                  }
+              }
+          }
+      }
+  }
+  else if (s[0] == 's') {
+      if (s[1] == 'e') {
+          if (s[2] == 't') {
+              if (s[3] == 't') {
+                  if (s[4] == 'e') {
+                      if (s[5] == 'r') {
+                          return Token_setter;
+                      }
+                  }
+              }
+          }
+      }
+  }
   else if (s[0] == 'o') {
     if (s[1] == 'n') {
       if (s[2] == 'e') {
@@ -104,15 +156,93 @@ static inline int classify6(const char *s) {
       }
     }
   }
+  else if (s[0] == 'r') {
+      if (s[1] == 'e') {
+          if (s[2] == 't') {
+              if (s[3] == 'a') {
+                  if (s[4] == 'i') {
+                      if (s[5] == 'n') {
+                          return Token_retain;
+                      }
+                  }
+              }
+          }
+      }
+  }
   return Token_identifier;
 }
 
+static inline int classify8(const char *s) {
+    if (s[0] == 'r') {
+        if (s[1] == 'e') {
+            if (s[2] == 'a') {
+                if (s[3] == 'd') {
+                    if (s[4] == 'o') {
+                        if (s[5] == 'n') {
+                            if (s[6] == 'l') {
+                                if (s[7] == 'y') {
+                                    return Token_readonly;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return Token_identifier;
+}
+
+static inline int classify9(const char *s) {
+    if (s[0] == 'n') {
+        if (s[1] == 'o') {
+            if (s[2] == 'n') {
+                if (s[3] == 'a') {
+                    if (s[4] == 't') {
+                        if (s[5] == 'o') {
+                            if (s[6] == 'm') {
+                                if (s[7] == 'i') {
+                                    if (s[8] == 'c') {
+                                        return Token_nonatomic;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    } else if (s[0] == 'r') {
+        if (s[1] == 'e') {
+            if (s[2] == 'a') {
+                if (s[3] == 'd') {
+                    if (s[4] == 'w') {
+                        if (s[5] == 'r') {
+                            if (s[6] == 'i') {
+                                if (s[7] == 't') {
+                                    if (s[8] == 'e') {
+                                        return Token_readwrite;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return Token_identifier;
+}
+
 int classifyObjectiveCTypeQualifiers(const char *s, int n) {
   switch (n) {
     case 2: return classify2(s);
     case 3: return classify3(s);
+    case 4: return classify4(s);
     case 5: return classify5(s);
     case 6: return classify6(s);
+    case 8: return classify8(s);
+    case 9: return classify9(s);
     default: return Token_identifier;
   } // switch
 }
diff --git a/src/shared/cplusplus/ObjectiveCTypeQualifiers.h b/src/shared/cplusplus/ObjectiveCTypeQualifiers.h
index 35a69e9299d407019b771b7990001b36ecf00805..0f9cdfd6774ab75fe4e8ef8665e06f97271cfff6 100644
--- a/src/shared/cplusplus/ObjectiveCTypeQualifiers.h
+++ b/src/shared/cplusplus/ObjectiveCTypeQualifiers.h
@@ -37,10 +37,18 @@ CPLUSPLUS_BEGIN_NAMESPACE
 enum {
   Token_in,
   Token_out,
+  Token_copy,
   Token_byref,
   Token_inout,
+  Token_assign,
   Token_bycopy,
+  Token_getter,
+  Token_retain,
+  Token_setter,
   Token_oneway,
+  Token_readonly,
+  Token_nonatomic,
+  Token_readwrite,
   Token_identifier
 };
 
diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp
index 45905829fc11948fcf8154864f9058f433f6be96..d335b5ebfff5cbc73eb6174857d6a6cce78ec245 100644
--- a/src/shared/cplusplus/Parser.cpp
+++ b/src/shared/cplusplus/Parser.cpp
@@ -4544,7 +4544,13 @@ bool Parser::parseObjCPropertyDeclaration(DeclarationAST *&node, SpecifierAST *a
                 last->comma_token = consumeToken();
                 last->next = new (_pool) ObjCPropertyAttributeListAST;
                 last = last->next;
-                parseObjCPropertyAttribute(last->attr);
+                if (!parseObjCPropertyAttribute(last->attr)) {
+                    _translationUnit->error(_tokenIndex, "expected token `%s' got `%s'",
+                                            Token::name(T_IDENTIFIER), tok().spell());
+                    while (LA() != T_RPAREN)
+                        consumeToken();
+                    break;
+                }
             }
         }
 
@@ -4597,15 +4603,15 @@ bool Parser::parseObjCMethodPrototype(ObjCMethodPrototypeAST *&node)
             lastArg->argument_declaration = declaration;
         }
 
-        // TODO EV: get this in the ast
         while (LA() == T_COMMA) {
             consumeToken();
 
             if (LA() == T_DOT_DOT_DOT) {
-                consumeToken();
+                ast->dot_dot_dot_token = consumeToken();
                 break;
             }
 
+            // TODO: Is this still valid, and if so, should it be stored in the AST? (EV)
             DeclarationAST *parameter_declaration = 0;
             parseParameterDeclaration(parameter_declaration);
         }
@@ -4639,28 +4645,43 @@ bool Parser::parseObjCPropertyAttribute(ObjCPropertyAttributeAST *&node)
         return false;
 
     node = new (_pool) ObjCPropertyAttributeAST;
-    match(T_IDENTIFIER, &(node->attribute_identifier_token));
-    if (LA() == T_EQUAL) {
-        node->equals_token = consumeToken();
 
-        unsigned identifier_token = 0;
-        match(T_IDENTIFIER, &identifier_token);
+    Identifier *id = tok().identifier;
+    const int k = classifyObjectiveCTypeQualifiers(id->chars(), id->size());
+    switch (k) {
+    case Token_copy:
+    case Token_assign:
+    case Token_retain:
+    case Token_readonly:
+    case Token_readwrite:
+    case Token_nonatomic:
+        node->attribute_identifier_token = consumeToken();
+        return true;
 
-        if (LA() == T_COLON) {
-            ObjCSelectorWithArgumentsAST *selector = new (_pool) ObjCSelectorWithArgumentsAST;
-            selector->selector_arguments = new (_pool) ObjCSelectorArgumentListAST;
-            selector->selector_arguments->argument = new (_pool) ObjCSelectorArgumentAST;
-            selector->selector_arguments->argument->name_token = identifier_token;
-            selector->selector_arguments->argument->colon_token = consumeToken();
-            node->method_selector = selector;
-        } else {
-            ObjCSelectorWithoutArgumentsAST *selector = new (_pool) ObjCSelectorWithoutArgumentsAST;
-            selector->name_token = identifier_token;
-            node->method_selector = selector;
-        }
+    case Token_getter: {
+        node->attribute_identifier_token = consumeToken();
+        match(T_EQUAL, &(node->equals_token));
+        ObjCSelectorWithoutArgumentsAST *selector = new (_pool) ObjCSelectorWithoutArgumentsAST;
+        match(T_IDENTIFIER, &(selector->name_token));
+        node->method_selector = selector;
+        return true;
     }
 
-    return true;
+    case Token_setter: {
+        node->attribute_identifier_token = consumeToken();
+        match(T_EQUAL, &(node->equals_token));
+        ObjCSelectorWithArgumentsAST *selector = new (_pool) ObjCSelectorWithArgumentsAST;
+        selector->selector_arguments = new (_pool) ObjCSelectorArgumentListAST;
+        selector->selector_arguments->argument = new (_pool) ObjCSelectorArgumentAST;
+        match(T_IDENTIFIER, &(selector->selector_arguments->argument->name_token));
+        match(T_COLON, &(selector->selector_arguments->argument->colon_token));
+        node->method_selector = selector;
+        return true;
+    }
+
+    default:
+        return false;
+    }
 }
 
 // objc-type-name ::= T_LPAREN objc-type-qualifiers-opt type-id T_RPAREN
diff --git a/src/shared/cplusplus/Symbol.h b/src/shared/cplusplus/Symbol.h
index d0de211a52399e8b67b2cffff2f82fc5481c7108..511e14c9f21def5bc3aa94af5869c6b19a70440b 100644
--- a/src/shared/cplusplus/Symbol.h
+++ b/src/shared/cplusplus/Symbol.h
@@ -210,6 +210,9 @@ public:
     /// Returns true if this Symbol is a ForwardClassDeclaration.
     bool isForwardClassDeclaration() const;
 
+    bool isObjCBaseClass() const;
+    bool isObjCBaseProtocol() const;
+
     /// Returns true if this Symbol is an Objective-C Class declaration.
     bool isObjCClass() const;
 
@@ -237,6 +240,8 @@ public:
     virtual const Argument *asArgument() const { return 0; }
     virtual const BaseClass *asBaseClass() const { return 0; }
     virtual const ForwardClassDeclaration *asForwardClassDeclaration() const { return 0; }
+    virtual const ObjCBaseClass *asObjCBaseClass() const { return 0; }
+    virtual const ObjCBaseProtocol *asObjCBaseProtocol() const { return 0; }
     virtual const ObjCClass *asObjCClass() const { return 0; }
     virtual const ObjCForwardClassDeclaration *asObjCForwardClassDeclaration() const { return 0; }
     virtual const ObjCProtocol *asObjCProtocol() const { return 0; }
@@ -255,6 +260,8 @@ public:
     virtual Argument *asArgument() { return 0; }
     virtual BaseClass *asBaseClass() { return 0; }
     virtual ForwardClassDeclaration *asForwardClassDeclaration() { return 0; }
+    virtual ObjCBaseClass *asObjCBaseClass() { return 0; }
+    virtual ObjCBaseProtocol *asObjCBaseProtocol() { return 0; }
     virtual ObjCClass *asObjCClass() { return 0; }
     virtual ObjCForwardClassDeclaration *asObjCForwardClassDeclaration() { return 0; }
     virtual ObjCProtocol *asObjCProtocol() { return 0; }
diff --git a/src/shared/cplusplus/SymbolVisitor.h b/src/shared/cplusplus/SymbolVisitor.h
index 939dad9068681723c531c84039ca6a1b75a5d58f..8708ab03212ea7c5a08f80a09441078e875e564c 100644
--- a/src/shared/cplusplus/SymbolVisitor.h
+++ b/src/shared/cplusplus/SymbolVisitor.h
@@ -81,6 +81,8 @@ public:
     virtual bool visit(ForwardClassDeclaration *) { return true; }
 
     // Objective-C
+    virtual bool visit(ObjCBaseClass *) { return true; }
+    virtual bool visit(ObjCBaseProtocol *) { return true; }
     virtual bool visit(ObjCClass *) { return true; }
     virtual bool visit(ObjCForwardClassDeclaration *) { return true; }
     virtual bool visit(ObjCProtocol *) { return true; }
diff --git a/src/shared/cplusplus/Symbols.cpp b/src/shared/cplusplus/Symbols.cpp
index c5259c9fe8396482400bcbea87a1e4fb0b44a631..d5fa07a99b9b103d09d7a5944b34a743de196ea2 100644
--- a/src/shared/cplusplus/Symbols.cpp
+++ b/src/shared/cplusplus/Symbols.cpp
@@ -561,6 +561,32 @@ void Class::visitSymbol0(SymbolVisitor *visitor)
     }
 }
 
+ObjCBaseClass::ObjCBaseClass(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+    : Symbol(translationUnit, sourceLocation, name)
+{ }
+
+ObjCBaseClass::~ObjCBaseClass()
+{ }
+
+FullySpecifiedType ObjCBaseClass::type() const
+{ return FullySpecifiedType(); }
+
+void ObjCBaseClass::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+ObjCBaseProtocol::ObjCBaseProtocol(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+    : Symbol(translationUnit, sourceLocation, name)
+{ }
+
+ObjCBaseProtocol::~ObjCBaseProtocol()
+{ }
+
+FullySpecifiedType ObjCBaseProtocol::type() const
+{ return FullySpecifiedType(); }
+
+void ObjCBaseProtocol::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
 ObjCClass::ObjCClass(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name):
         ScopedSymbol(translationUnit, sourceLocation, name),
         _categoryName(0),
diff --git a/src/shared/cplusplus/Symbols.h b/src/shared/cplusplus/Symbols.h
index 3ac7182c9a0e1f200e3294a343bd925fe126fbb1..10eb0366bffce04386977009c63551c182c9ec69 100644
--- a/src/shared/cplusplus/Symbols.h
+++ b/src/shared/cplusplus/Symbols.h
@@ -476,6 +476,48 @@ private:
     Array<BaseClass *> _baseClasses;
 };
 
+class CPLUSPLUS_EXPORT ObjCBaseClass: public Symbol
+{
+public:
+    ObjCBaseClass(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+    virtual ~ObjCBaseClass();
+
+    // Symbol's interface
+    virtual FullySpecifiedType type() const;
+
+    virtual const ObjCBaseClass *asObjCBaseClass() const
+    { return this; }
+
+    virtual ObjCBaseClass *asObjCBaseClass()
+    { return this; }
+
+protected:
+    virtual void visitSymbol0(SymbolVisitor *visitor);
+
+private:
+};
+
+class CPLUSPLUS_EXPORT ObjCBaseProtocol: public Symbol
+{
+public:
+    ObjCBaseProtocol(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+    virtual ~ObjCBaseProtocol();
+
+    // Symbol's interface
+    virtual FullySpecifiedType type() const;
+
+    virtual const ObjCBaseProtocol *asObjCBaseProtocol() const
+    { return this; }
+
+    virtual ObjCBaseProtocol *asObjCBaseProtocol()
+    { return this; }
+
+protected:
+    virtual void visitSymbol0(SymbolVisitor *visitor);
+
+private:
+};
+
 class CPLUSPLUS_EXPORT ObjCForwardProtocolDeclaration: public Symbol, public Type
 {
 public:
@@ -511,6 +553,15 @@ public:
     ObjCProtocol(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
     virtual ~ObjCProtocol();
 
+    unsigned protocolCount() const
+    { return _protocols.count(); }
+
+    ObjCBaseProtocol *protocolAt(unsigned index) const
+    { return _protocols.at(index); }
+
+    void addProtocol(ObjCBaseProtocol *protocol)
+    { _protocols.push_back(protocol); }
+
     // Symbol's interface
     virtual FullySpecifiedType type() const;
 
@@ -534,7 +585,7 @@ protected:
     virtual void accept0(TypeVisitor *visitor);
 
 private:
-    Array<ObjCProtocol *> _protocols;
+    Array<ObjCBaseProtocol *> _protocols;
 };
 
 class CPLUSPLUS_EXPORT ObjCForwardClassDeclaration: public Symbol, public Type
@@ -579,18 +630,18 @@ public:
     Name *categoryName() const { return _categoryName; }
     void setCategoryName(Name *categoryName) { _categoryName = categoryName; }
 
-    ObjCClass *baseClass() const
+    ObjCBaseClass *baseClass() const
     { return _baseClass; }
-    void setBaseClass(ObjCClass *baseClass)
+    void setBaseClass(ObjCBaseClass *baseClass)
     { _baseClass = baseClass; }
 
     unsigned protocolCount() const
     { return _protocols.count(); }
 
-    ObjCProtocol *protocolAt(unsigned index) const
+    ObjCBaseProtocol *protocolAt(unsigned index) const
     { return _protocols.at(index); }
 
-    void addProtocol(ObjCProtocol *protocol)
+    void addProtocol(ObjCBaseProtocol *protocol)
     { _protocols.push_back(protocol); }
 
     // Symbol's interface
@@ -618,8 +669,8 @@ protected:
 private:
     bool _isInterface;
     Name *_categoryName;
-    ObjCClass * _baseClass;
-    Array<ObjCProtocol *> _protocols;
+    ObjCBaseClass * _baseClass;
+    Array<ObjCBaseProtocol *> _protocols;
 };
 
 class CPLUSPLUS_EXPORT ObjCMethod: public ScopedSymbol, public Type