diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 03e6a9f28db1366d696de2570fa483721914301d..d6c23a700cdac2ce0ef42758805292df96f674e2 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -666,6 +666,119 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) return index; } +void CppCodeCompletion::completeObjCMsgSend(ClassOrNamespace *binding, + bool staticClassAccess) +{ + QList<Scope*> memberScopes; + foreach (Symbol *s, binding->symbols()) { + if (ObjCClass *c = s->asObjCClass()) + memberScopes.append(c->members()); + } + + foreach (Scope *scope, memberScopes) { + for (unsigned i = 0; i < scope->symbolCount(); ++i) { + Symbol *symbol = scope->symbolAt(i); + + if (ObjCMethod *method = symbol->type()->asObjCMethodType()) { + if (method->isStatic() == staticClassAccess) { + Overview oo; + const SelectorNameId *selectorName = + method->name()->asSelectorNameId(); + QString text; + QString data; + if (selectorName->hasArguments()) { + for (unsigned i = 0; i < selectorName->nameCount(); ++i) { + if (i > 0) + text += QLatin1Char(' '); + Symbol *arg = method->argumentAt(i); + text += selectorName->nameAt(i)->identifier()->chars(); + text += QLatin1Char(':'); + text += QChar::ObjectReplacementCharacter; + text += QLatin1Char('('); + text += oo(arg->type()); + text += QLatin1Char(')'); + text += oo(arg->name()); + text += QChar::ObjectReplacementCharacter; + } + } else { + text = selectorName->identifier()->chars(); + } + data = text; + + if (!text.isEmpty()) { + TextEditor::CompletionItem item(this); + item.text = text; + item.data = QVariant::fromValue(data); + m_completions.append(item); + } + } + } + } + } +} + +bool CppCodeCompletion::tryObjCCompletion(TextEditor::BaseTextEditor *edit) +{ + Q_ASSERT(edit); + + int end = m_editor->position(); + while (m_editor->characterAt(end).isSpace()) + ++end; + if (m_editor->characterAt(end) != QLatin1Char(']')) + return false; + + QTextCursor tc(edit->document()); + tc.setPosition(end); + BackwardsScanner tokens(tc); + if (tokens[tokens.startToken() - 1].isNot(T_RBRACKET)) + return false; + + const int start = tokens.startOfMatchingBrace(tokens.startToken()); + if (start == tokens.startToken()) + return false; + + const int startPos = tokens[start].begin() + tokens.startPosition(); + const QString expr = m_editor->textAt(startPos, m_editor->position() - startPos); + + const Snapshot snapshot = m_manager->snapshot(); + Document::Ptr thisDocument = snapshot.document(m_editor->file()->fileName()); + if (! thisDocument) + return false; + + typeOfExpression.init(thisDocument, snapshot); + int line = 0, column = 0; + edit->convertPosition(m_editor->position(), &line, &column); + Scope *scope = thisDocument->scopeAt(line, column); + if (!scope) + return false; + + const QList<LookupItem> items = typeOfExpression(expr, scope); + LookupContext lookupContext(thisDocument, snapshot); + + foreach (const LookupItem &item, items) { + FullySpecifiedType ty = item.type().simplified(); + if (ty->isPointerType()) { + ty = ty->asPointerType()->elementType().simplified(); + + if (NamedType *namedTy = ty->asNamedType()) { + ClassOrNamespace *binding = lookupContext.lookupType(namedTy->name(), item.scope()); + completeObjCMsgSend(binding, false); + } + } else { + if (ObjCClass *clazz = ty->asObjCClassType()) { + ClassOrNamespace *binding = lookupContext.lookupType(clazz->name(), item.scope()); + completeObjCMsgSend(binding, true); + } + } + } + + if (m_completions.isEmpty()) + return false; + + m_startPosition = m_editor->position(); + return true; +} + int CppCodeCompletion::startCompletionHelper(TextEditor::ITextEditable *editor) { TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget()); @@ -674,6 +787,11 @@ int CppCodeCompletion::startCompletionHelper(TextEditor::ITextEditable *editor) m_editor = editor; + if (m_objcEnabled) { + if (tryObjCCompletion(edit)) + return m_startPosition; + } + const int startOfName = findStartOfName(); m_startPosition = startOfName; m_completionOperator = T_EOF_SYMBOL; diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h index 7d04c301850e00da9c8af87301283179b4294c5b..513b038407a969fa04edfd87d69389c97112f8fc 100644 --- a/src/plugins/cpptools/cppcodecompletion.h +++ b/src/plugins/cpptools/cppcodecompletion.h @@ -133,6 +133,9 @@ private: QList<TextEditor::CompletionItem> removeDuplicates(const QList<TextEditor::CompletionItem> &items); private: + void completeObjCMsgSend(CPlusPlus::ClassOrNamespace *binding, + bool staticClassAccess); + bool tryObjCCompletion(TextEditor::BaseTextEditor *edit); bool objcKeywordsWanted() const; static QStringList preprocessorCompletions;