diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 3b76923392d9c5cc9ce5b074f23c5c6f58c6aa64..ec58883712fb1338a61fe4d926b651680476f900 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -50,6 +50,7 @@ #include <cplusplus/MatchingText.h> #include <cplusplus/Overview.h> #include <cplusplus/ExpressionUnderCursor.h> +#include <cplusplus/BackwardsScanner.h> #include <cplusplus/TokenUnderCursor.h> #include <coreplugin/icore.h> @@ -860,7 +861,8 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) } if (! resolvedTypes.isEmpty()) { - if (m_completionOperator == T_LPAREN && completeConstructorOrFunction(resolvedTypes, context)) { + if (m_completionOperator == T_LPAREN && + completeConstructorOrFunction(resolvedTypes, context, endOfExpression)) { return m_startPosition; } else if ((m_completionOperator == T_DOT || m_completionOperator == T_ARROW) && @@ -899,7 +901,7 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) // If it's a class, add completions for the constructors foreach (const TypeOfExpression::Result &result, results) { if (result.first->isClassType()) { - if (completeConstructorOrFunction(results, context)) + if (completeConstructorOrFunction(results, context, endOfExpression)) return m_startPosition; break; } @@ -912,7 +914,8 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) } bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpression::Result> &results, - const LookupContext &context) + const LookupContext &context, + int endOfExpression) { QList<Function *> functions; @@ -1002,6 +1005,77 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi } if (! functions.isEmpty()) { + // There are two options: + // 1. If this is a function call, we want to pop up a tooltip that shows the user + // the possible overloads with their argument types and names. + // 2. If this is a function definition, we want to offer autocompletion of + // the function signature. + + // Here we evaluate a first criterion: function definitions will only + // happen in class or namespace scope. + + // get current line and column + TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(m_editor->widget()); + int lineSigned = 0, columnSigned = 0; + edit->convertPosition(m_editor->position(), &lineSigned, &columnSigned); + unsigned line = lineSigned, column = columnSigned; + + // find a scope that encloses the current location, starting from the lastVisibileSymbol + // and moving outwards + Scope *sc = context.symbol()->scope(); + while (sc->enclosingScope()) { + unsigned startLine, startColumn; + context.thisDocument()->translationUnit()->getPosition(sc->owner()->startOffset(), &startLine, &startColumn); + unsigned endLine, endColumn; + context.thisDocument()->translationUnit()->getPosition(sc->owner()->endOffset(), &endLine, &endColumn); + + if (startLine <= line && line <= endLine) + if ((startLine != line || startColumn <= column) + && (endLine != line || column <= endColumn)) + break; + + sc = sc->enclosingScope(); + } + + if (sc->isClassScope() || sc->isNamespaceScope()) + { + // It may still be a function call. If the whole line parses as a function + // declaration, we should be certain that it isn't. + bool autocompleteSignature = false; + + QTextCursor tc(edit->document()); + tc.setPosition(endOfExpression); + BackwardsScanner bs(tc); + QString possibleDecl = bs.mid(bs.startOfLine(bs.startToken())).trimmed().append("();"); + + Document::Ptr doc = Document::create(QLatin1String("<completion>")); + doc->setSource(possibleDecl.toLatin1()); + if (doc->parse(Document::ParseDeclaration)) { + doc->check(); + if (SimpleDeclarationAST *sd = doc->translationUnit()->ast()->asSimpleDeclaration()) { + if (sd->declarators->declarator->postfix_declarators + && sd->declarators->declarator->postfix_declarators->asFunctionDeclarator()) { + autocompleteSignature = true; + } + } + } + + if (autocompleteSignature) { + // set up signature autocompletion + foreach (Function *f, functions) { + Overview overview; + overview.setShowArgumentNames(true); + + TextEditor::CompletionItem item(this); + item.text = overview(f->type()); + item.text = item.text.mid(1, item.text.size()-2); + m_completions.append(item); + } + return true; + } + } + + // set up function call tooltip // Recreate if necessary if (!m_functionArgumentWidget) diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h index cadb93bf1a3f1f8104dc5eb613ca87a5bf378843..56cf85150e8613e12836e51f93220ac9f05965e6 100644 --- a/src/plugins/cpptools/cppcodecompletion.h +++ b/src/plugins/cpptools/cppcodecompletion.h @@ -117,7 +117,8 @@ private: bool completeInclude(const QTextCursor &cursor); bool completeConstructorOrFunction(const QList<CPlusPlus::TypeOfExpression::Result> &, - const CPlusPlus::LookupContext &); + const CPlusPlus::LookupContext &, + int endOfExpression); bool completeMember(const QList<CPlusPlus::TypeOfExpression::Result> &, const CPlusPlus::LookupContext &context);