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 ¯oName, 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