forked from qt-creator/qt-creator
		
	Added ObjC completion for message-send expressions.
This commit is contained in:
		@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user