diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 5a0dbefa4ad74f48f1a7e58e57260d26f1cdb085..b231815d6d765d08c5bf137a5a169c94c05cdc13 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -152,7 +152,7 @@ public:
     {
     }
 
-    virtual int argumentCount() const
+    virtual int namedArgumentCount() const
     {
         return _method.parameterNames().size();
     }
@@ -1219,7 +1219,7 @@ const Value *FunctionValue::returnValue() const
     return valueOwner()->unknownValue();
 }
 
-int FunctionValue::argumentCount() const
+int FunctionValue::namedArgumentCount() const
 {
     return 0;
 }
@@ -1234,6 +1234,11 @@ QString FunctionValue::argumentName(int index) const
     return QString::fromLatin1("arg%1").arg(index + 1);
 }
 
+int FunctionValue::optionalNamedArgumentCount() const
+{
+    return 0;
+}
+
 bool FunctionValue::isVariadic() const
 {
     return true;
@@ -1255,7 +1260,10 @@ void FunctionValue::accept(ValueVisitor *visitor) const
 }
 
 Function::Function(ValueOwner *valueOwner)
-    : FunctionValue(valueOwner), _returnValue(0)
+    : FunctionValue(valueOwner)
+    , _returnValue(0)
+    , _optionalNamedArgumentCount(0)
+    , _isVariadic(false)
 {
     setClassName("Function");
 }
@@ -1284,11 +1292,26 @@ void Function::setReturnValue(const Value *returnValue)
     _returnValue = returnValue;
 }
 
-int Function::argumentCount() const
+void Function::setVariadic(bool variadic)
+{
+    _isVariadic = variadic;
+}
+
+void Function::setOptionalNamedArgumentCount(int count)
+{
+    _optionalNamedArgumentCount = count;
+}
+
+int Function::namedArgumentCount() const
 {
     return _arguments.size();
 }
 
+int Function::optionalNamedArgumentCount() const
+{
+    return _optionalNamedArgumentCount;
+}
+
 const Value *Function::argument(int index) const
 {
     return _arguments.at(index);
@@ -1309,6 +1332,11 @@ const Value *Function::invoke(const Activation *) const
     return _returnValue;
 }
 
+bool Function::isVariadic() const
+{
+    return _isVariadic;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // typing environment
 ////////////////////////////////////////////////////////////////////////////////
@@ -1879,13 +1907,47 @@ bool ASTVariableReference::getSourceLocation(QString *fileName, int *line, int *
     return true;
 }
 
+namespace {
+class UsesArgumentsArray : protected Visitor
+{
+    bool _usesArgumentsArray;
+
+public:
+    bool operator()(FunctionBody *ast)
+    {
+        if (!ast || !ast->elements)
+            return false;
+        _usesArgumentsArray = false;
+        Node::accept(ast->elements, this);
+        return _usesArgumentsArray;
+    }
+
+protected:
+    bool visit(ArrayMemberExpression *ast)
+    {
+        if (IdentifierExpression *idExp = cast<IdentifierExpression *>(ast->base)) {
+            if (idExp->name == QLatin1String("arguments"))
+                _usesArgumentsArray = true;
+        }
+        return true;
+    }
+
+    // don't go into nested functions
+    bool visit(FunctionBody *) { return false; }
+};
+} // anonymous namespace
+
 ASTFunctionValue::ASTFunctionValue(FunctionExpression *ast, const Document *doc, ValueOwner *valueOwner)
-    : FunctionValue(valueOwner), _ast(ast), _doc(doc)
+    : FunctionValue(valueOwner)
+    , _ast(ast)
+    , _doc(doc)
 {
     setPrototype(valueOwner->functionPrototype());
 
     for (FormalParameterList *it = ast->formals; it; it = it->next)
         _argumentNames.append(it->name.toString());
+
+    _isVariadic = UsesArgumentsArray()(ast->body);
 }
 
 ASTFunctionValue::~ASTFunctionValue()
@@ -1897,7 +1959,7 @@ FunctionExpression *ASTFunctionValue::ast() const
     return _ast;
 }
 
-int ASTFunctionValue::argumentCount() const
+int ASTFunctionValue::namedArgumentCount() const
 {
     return _argumentNames.size();
 }
@@ -1913,6 +1975,11 @@ QString ASTFunctionValue::argumentName(int index) const
     return FunctionValue::argumentName(index);
 }
 
+bool ASTFunctionValue::isVariadic() const
+{
+    return _isVariadic;
+}
+
 bool ASTFunctionValue::getSourceLocation(QString *fileName, int *line, int *column) const
 {
     *fileName = _doc->fileName();
@@ -2021,7 +2088,7 @@ const ASTSignal *ASTSignal::asAstSignal() const
     return this;
 }
 
-int ASTSignal::argumentCount() const
+int ASTSignal::namedArgumentCount() const
 {
     int count = 0;
     for (UiParameterList *it = _ast->parameters; it; it = it->next)
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index f989d5f3a13872d600e13f8130614b6efc0ce864..c13f3d6b9a038c81b2d98e9008e4925630fab715 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -583,11 +583,24 @@ public:
 
     virtual const Value *returnValue() const;
 
-    virtual int argumentCount() const;
-    virtual const Value *argument(int index) const;
+    // Access to the names of arguments
+    // Named arguments can be optional (usually known for builtins only)
+    virtual int namedArgumentCount() const;
     virtual QString argumentName(int index) const;
+
+    // The number of optional named arguments
+    // Example: JSON.stringify(value[, replacer[, space]])
+    //          has namedArgumentCount = 3
+    //          and optionalNamedArgumentCount = 2
+    virtual int optionalNamedArgumentCount() const;
+
+    // Whether the function accepts an unlimited number of arguments
+    // after the named ones. Defaults to false.
+    // Example: Math.max(...)
     virtual bool isVariadic() const;
 
+    virtual const Value *argument(int index) const;
+
     virtual const Value *invoke(const Activation *activation) const;
 
     // Value interface
@@ -603,18 +616,24 @@ public:
 
     void addArgument(const Value *argument, const QString &name = QString());
     void setReturnValue(const Value *returnValue);
+    void setVariadic(bool variadic);
+    void setOptionalNamedArgumentCount(int count);
 
     // FunctionValue interface
     virtual const Value *returnValue() const;
-    virtual int argumentCount() const;
+    virtual int namedArgumentCount() const;
+    virtual int optionalNamedArgumentCount() const;
     virtual const Value *argument(int index) const;
     virtual QString argumentName(int index) const;
     virtual const Value *invoke(const Activation *activation) const;
+    virtual bool isVariadic() const;
 
 private:
     ValueList _arguments;
     QStringList _argumentNames;
     const Value *_returnValue;
+    int _optionalNamedArgumentCount;
+    bool _isVariadic;
 };
 
 
@@ -799,6 +818,7 @@ class QMLJS_EXPORT ASTFunctionValue: public FunctionValue
     AST::FunctionExpression *_ast;
     const Document *_doc;
     QList<QString> _argumentNames;
+    bool _isVariadic;
 
 public:
     ASTFunctionValue(AST::FunctionExpression *ast, const Document *doc, ValueOwner *valueOwner);
@@ -806,8 +826,9 @@ public:
 
     AST::FunctionExpression *ast() const;
 
-    virtual int argumentCount() const;
+    virtual int namedArgumentCount() const;
     virtual QString argumentName(int index) const;
+    virtual bool isVariadic() const;
 
     virtual bool getSourceLocation(QString *fileName, int *line, int *column) const;
 };
@@ -851,7 +872,7 @@ public:
     const ObjectValue *bodyScope() const { return _bodyScope; }
 
     // FunctionValue interface
-    virtual int argumentCount() const;
+    virtual int namedArgumentCount() const;
     virtual const Value *argument(int index) const;
     virtual QString argumentName(int index) const;
 
diff --git a/src/libs/qmljs/qmljsvalueowner.cpp b/src/libs/qmljs/qmljsvalueowner.cpp
index 5fa3635ecd069d73f7b888e012b4fefe27ed55a4..0b3a7bd265281ae7e5b3f4f59c5cf602b760acf4 100644
--- a/src/libs/qmljs/qmljsvalueowner.cpp
+++ b/src/libs/qmljs/qmljsvalueowner.cpp
@@ -499,21 +499,20 @@ QString ValueOwner::typeId(const Value *value)
     return _typeId(value);
 }
 
-Function *ValueOwner::addFunction(ObjectValue *object, const QString &name, const Value *result, int argumentCount)
+Function *ValueOwner::addFunction(ObjectValue *object, const QString &name, const Value *result, int argumentCount, int optionalCount, bool variadic)
 {
-    Function *function = newFunction();
+    Function *function = addFunction(object, name, argumentCount, optionalCount, variadic);
     function->setReturnValue(result);
-    for (int i = 0; i < argumentCount; ++i)
-        function->addArgument(unknownValue());
-    object->setMember(name, function);
     return function;
 }
 
-Function *ValueOwner::addFunction(ObjectValue *object, const QString &name, int argumentCount)
+Function *ValueOwner::addFunction(ObjectValue *object, const QString &name, int argumentCount, int optionalCount, bool variadic)
 {
     Function *function = newFunction();
     for (int i = 0; i < argumentCount; ++i)
         function->addArgument(unknownValue());
+    function->setVariadic(variadic);
+    function->setOptionalNamedArgumentCount(optionalCount);
     object->setMember(name, function);
     return function;
 }
@@ -538,46 +537,58 @@ void ValueOwner::initializePrototypes()
     _objectCtor->setPrototype(_functionPrototype);
     _objectCtor->setMember("prototype", _objectPrototype);
     _objectCtor->setReturnValue(newObject());
+    _objectCtor->addArgument(unknownValue(), "value");
+    _objectCtor->setOptionalNamedArgumentCount(1);
 
     _functionCtor = new FunctionCtor(this);
     _functionCtor->setPrototype(_functionPrototype);
     _functionCtor->setMember("prototype", _functionPrototype);
     _functionCtor->setReturnValue(newFunction());
+    _functionCtor->setVariadic(true);
 
     _arrayCtor = new ArrayCtor(this);
     _arrayCtor->setPrototype(_functionPrototype);
     _arrayCtor->setMember("prototype", _arrayPrototype);
     _arrayCtor->setReturnValue(newArray());
+    _arrayCtor->setVariadic(true);
 
     _stringCtor = new StringCtor(this);
     _stringCtor->setPrototype(_functionPrototype);
     _stringCtor->setMember("prototype", _stringPrototype);
     _stringCtor->setReturnValue(stringValue());
+    _stringCtor->addArgument(unknownValue(), "value");
+    _stringCtor->setOptionalNamedArgumentCount(1);
 
     _booleanCtor = new BooleanCtor(this);
     _booleanCtor->setPrototype(_functionPrototype);
     _booleanCtor->setMember("prototype", _booleanPrototype);
     _booleanCtor->setReturnValue(booleanValue());
+    _booleanCtor->addArgument(unknownValue(), "value");
 
     _numberCtor = new NumberCtor(this);
     _numberCtor->setPrototype(_functionPrototype);
     _numberCtor->setMember("prototype", _numberPrototype);
     _numberCtor->setReturnValue(numberValue());
+    _numberCtor->addArgument(unknownValue(), "value");
+    _numberCtor->setOptionalNamedArgumentCount(1);
 
     _dateCtor = new DateCtor(this);
     _dateCtor->setPrototype(_functionPrototype);
     _dateCtor->setMember("prototype", _datePrototype);
     _dateCtor->setReturnValue(_datePrototype);
+    _dateCtor->setVariadic(true);
 
     _regexpCtor = new RegExpCtor(this);
     _regexpCtor->setPrototype(_functionPrototype);
     _regexpCtor->setMember("prototype", _regexpPrototype);
     _regexpCtor->setReturnValue(_regexpPrototype);
+    _regexpCtor->addArgument(unknownValue(), "pattern");
+    _regexpCtor->addArgument(unknownValue(), "flags");
 
     addFunction(_objectCtor, "getPrototypeOf", 1);
     addFunction(_objectCtor, "getOwnPropertyDescriptor", 2);
     addFunction(_objectCtor, "getOwnPropertyNames", newArray(), 1);
-    addFunction(_objectCtor, "create", 1);
+    addFunction(_objectCtor, "create", 1, 1);
     addFunction(_objectCtor, "defineProperty", 3);
     addFunction(_objectCtor, "defineProperties", 2);
     addFunction(_objectCtor, "seal", 1);
@@ -599,8 +610,8 @@ void ValueOwner::initializePrototypes()
     _functionPrototype->setMember("constructor", _functionCtor);
     addFunction(_functionPrototype, "toString", stringValue(), 0);
     addFunction(_functionPrototype, "apply", 2);
-    addFunction(_functionPrototype, "call", 1);
-    addFunction(_functionPrototype, "bind", 1);
+    addFunction(_functionPrototype, "call", 1, 0, true);
+    addFunction(_functionPrototype, "bind", 1, 0, true);
 
     // set up the default Array prototype
     addFunction(_arrayCtor, "isArray", booleanValue(), 1);
@@ -608,35 +619,35 @@ void ValueOwner::initializePrototypes()
     _arrayPrototype->setMember("constructor", _arrayCtor);
     addFunction(_arrayPrototype, "toString", stringValue(), 0);
     addFunction(_arrayPrototype, "toLocalString", stringValue(), 0);
-    addFunction(_arrayPrototype, "concat", 0);
+    addFunction(_arrayPrototype, "concat", 0, 0, true);
     addFunction(_arrayPrototype, "join", 1);
     addFunction(_arrayPrototype, "pop", 0);
-    addFunction(_arrayPrototype, "push", 0);
+    addFunction(_arrayPrototype, "push", 0, 0, true);
     addFunction(_arrayPrototype, "reverse", 0);
     addFunction(_arrayPrototype, "shift", 0);
     addFunction(_arrayPrototype, "slice", 2);
     addFunction(_arrayPrototype, "sort", 1);
     addFunction(_arrayPrototype, "splice", 2);
-    addFunction(_arrayPrototype, "unshift", 0);
-    addFunction(_arrayPrototype, "indexOf", numberValue(), 1);
-    addFunction(_arrayPrototype, "lastIndexOf", numberValue(), 1);
-    addFunction(_arrayPrototype, "every", 1);
-    addFunction(_arrayPrototype, "some", 1);
-    addFunction(_arrayPrototype, "forEach", 1);
-    addFunction(_arrayPrototype, "map", 1);
-    addFunction(_arrayPrototype, "filter", 1);
-    addFunction(_arrayPrototype, "reduce", 1);
-    addFunction(_arrayPrototype, "reduceRight", 1);
+    addFunction(_arrayPrototype, "unshift", 0, 0, true);
+    addFunction(_arrayPrototype, "indexOf", numberValue(), 2, 1);
+    addFunction(_arrayPrototype, "lastIndexOf", numberValue(), 2, 1);
+    addFunction(_arrayPrototype, "every", 2, 1);
+    addFunction(_arrayPrototype, "some", 2, 1);
+    addFunction(_arrayPrototype, "forEach", 2, 1);
+    addFunction(_arrayPrototype, "map", 2, 1);
+    addFunction(_arrayPrototype, "filter", 2, 1);
+    addFunction(_arrayPrototype, "reduce", 2, 1);
+    addFunction(_arrayPrototype, "reduceRight", 2, 1);
 
     // set up the default String prototype
-    addFunction(_stringCtor, "fromCharCode", stringValue(), 0);
+    addFunction(_stringCtor, "fromCharCode", stringValue(), 0, 0, true);
 
     _stringPrototype->setMember("constructor", _stringCtor);
     addFunction(_stringPrototype, "toString", stringValue(), 0);
     addFunction(_stringPrototype, "valueOf", stringValue(), 0);
     addFunction(_stringPrototype, "charAt", stringValue(), 1);
     addFunction(_stringPrototype, "charCodeAt", stringValue(), 1);
-    addFunction(_stringPrototype, "concat", stringValue(), 0);
+    addFunction(_stringPrototype, "concat", stringValue(), 0, 0, true);
     addFunction(_stringPrototype, "indexOf", numberValue(), 2);
     addFunction(_stringPrototype, "lastIndexOf", numberValue(), 2);
     addFunction(_stringPrototype, "localeCompare", booleanValue(), 1);
@@ -669,7 +680,7 @@ void ValueOwner::initializePrototypes()
     addFunction(_numberCtor, "fromCharCode", 0);
 
     _numberPrototype->setMember("constructor", _numberCtor);
-    addFunction(_numberPrototype, "toString", stringValue(), 0);
+    addFunction(_numberPrototype, "toString", stringValue(), 1, 1);
     addFunction(_numberPrototype, "toLocaleString", stringValue(), 0);
     addFunction(_numberPrototype, "valueOf", numberValue(), 0);
     addFunction(_numberPrototype, "toFixed", numberValue(), 1);
@@ -697,8 +708,8 @@ void ValueOwner::initializePrototypes()
     addFunction(_mathObject, "exp", numberValue(), 1);
     addFunction(_mathObject, "floor", numberValue(), 1);
     addFunction(_mathObject, "log", numberValue(), 1);
-    addFunction(_mathObject, "max", numberValue(), 0);
-    addFunction(_mathObject, "min", numberValue(), 0);
+    addFunction(_mathObject, "max", numberValue(), 0, 0, true);
+    addFunction(_mathObject, "min", numberValue(), 0, 0, true);
     addFunction(_mathObject, "pow", numberValue(), 2);
     addFunction(_mathObject, "random", numberValue(), 1);
     addFunction(_mathObject, "round", numberValue(), 1);
@@ -708,6 +719,7 @@ void ValueOwner::initializePrototypes()
 
     // set up the default Boolean prototype
     addFunction(_dateCtor, "parse", numberValue(), 1);
+    addFunction(_dateCtor, "UTC", numberValue(), 7, 5);
     addFunction(_dateCtor, "now", numberValue(), 0);
 
     _datePrototype->setMember("constructor", _dateCtor);
@@ -737,18 +749,18 @@ void ValueOwner::initializePrototypes()
     addFunction(_datePrototype, "setTime", 1);
     addFunction(_datePrototype, "setMilliseconds", 1);
     addFunction(_datePrototype, "setUTCMilliseconds", 1);
-    addFunction(_datePrototype, "setSeconds", 1);
-    addFunction(_datePrototype, "setUTCSeconds", 1);
-    addFunction(_datePrototype, "setMinutes", 1);
-    addFunction(_datePrototype, "setUTCMinutes", 1);
-    addFunction(_datePrototype, "setHours", 1);
-    addFunction(_datePrototype, "setUTCHours", 1);
+    addFunction(_datePrototype, "setSeconds", 2, 1);
+    addFunction(_datePrototype, "setUTCSeconds", 2, 1);
+    addFunction(_datePrototype, "setMinutes", 3, 2);
+    addFunction(_datePrototype, "setUTCMinutes", 3, 2);
+    addFunction(_datePrototype, "setHours", 4, 3);
+    addFunction(_datePrototype, "setUTCHours", 4, 3);
     addFunction(_datePrototype, "setDate", 1);
     addFunction(_datePrototype, "setUTCDate", 1);
-    addFunction(_datePrototype, "setMonth", 1);
-    addFunction(_datePrototype, "setUTCMonth", 1);
-    addFunction(_datePrototype, "setFullYear", 1);
-    addFunction(_datePrototype, "setUTCFullYear", 1);
+    addFunction(_datePrototype, "setMonth", 2, 1);
+    addFunction(_datePrototype, "setUTCMonth", 2, 1);
+    addFunction(_datePrototype, "setFullYear", 3, 2);
+    addFunction(_datePrototype, "setUTCFullYear", 3, 2);
     addFunction(_datePrototype, "toUTCString", stringValue(), 0);
     addFunction(_datePrototype, "toISOString", stringValue(), 0);
     addFunction(_datePrototype, "toJSON", stringValue(), 1);
@@ -829,10 +841,12 @@ void ValueOwner::initializePrototypes()
     f = addFunction(json, "parse", objectPrototype());
     f->addArgument(stringValue(), "text");
     f->addArgument(functionPrototype(), "reviver");
+    f->setOptionalNamedArgumentCount(1);
     f = addFunction(json, "stringify", stringValue());
     f->addArgument(unknownValue(), "value");
     f->addArgument(unknownValue(), "replacer");
     f->addArgument(unknownValue(), "space");
+    f->setOptionalNamedArgumentCount(2);
     _globalObject->setMember("JSON", json);
 
     // global Qt object, in alphabetic order
diff --git a/src/libs/qmljs/qmljsvalueowner.h b/src/libs/qmljs/qmljsvalueowner.h
index 0a4a33cf0e6e4f1749d21d97f66e3609cd51008a..d1edfe024851f0870794a522a150553ecad00027 100644
--- a/src/libs/qmljs/qmljsvalueowner.h
+++ b/src/libs/qmljs/qmljsvalueowner.h
@@ -142,8 +142,10 @@ public:
 private:
     void initializePrototypes();
 
-    Function *addFunction(ObjectValue *object, const QString &name, const Value *result, int argumentCount = 0);
-    Function *addFunction(ObjectValue *object, const QString &name, int argumentCount = 0);
+    Function *addFunction(ObjectValue *object, const QString &name, const Value *result,
+                          int argumentCount = 0, int optionalCount = 0, bool variadic = false);
+    Function *addFunction(ObjectValue *object, const QString &name,
+                          int argumentCount = 0, int optionalCount = 0, bool variadic = false);
 
 private:
     ObjectValue *_objectPrototype;
diff --git a/src/plugins/qmljseditor/qmljscompletionassist.cpp b/src/plugins/qmljseditor/qmljscompletionassist.cpp
index 25b451decf6ab26444e2908974329be6b64b721c..ac594e9770d777e16297f6c5e23c0591a99613d9 100644
--- a/src/plugins/qmljseditor/qmljscompletionassist.cpp
+++ b/src/plugins/qmljseditor/qmljscompletionassist.cpp
@@ -41,6 +41,8 @@
 #include <texteditor/codeassist/genericproposal.h>
 #include <texteditor/codeassist/functionhintproposal.h>
 #include <texteditor/codeassist/ifunctionhintproposalmodel.h>
+#include <texteditor/texteditorsettings.h>
+#include <texteditor/completionsettings.h>
 
 #include <utils/qtcassert.h>
 
@@ -111,6 +113,13 @@ public:
     virtual void operator()(const Value *base, const QString &name, const Value *value) = 0;
 };
 
+class CompleteFunctionCall
+{
+public:
+    CompleteFunctionCall(bool hasArguments = true) : hasArguments(hasArguments) {}
+    bool hasArguments;
+};
+
 class CompletionAdder : public PropertyProcessor
 {
 protected:
@@ -127,8 +136,15 @@ public:
     virtual void operator()(const Value *base, const QString &name, const Value *value)
     {
         Q_UNUSED(base)
-        Q_UNUSED(value)
-        addCompletion(completions, name, icon, order);
+        QVariant data;
+        if (const FunctionValue *func = value->asFunctionValue()) {
+            // constructors usually also have other interesting members,
+            // don't consider them pure functions and complete the '()'
+            if (!func->lookupMember("prototype", 0, 0, false)) {
+                data = QVariant::fromValue(CompleteFunctionCall(func->namedArgumentCount() || func->isVariadic()));
+            }
+        }
+        addCompletion(completions, name, icon, order, data);
     }
 
     QIcon icon;
@@ -319,6 +335,8 @@ bool isLiteral(AST::Node *ast)
 
 } // Anonymous
 
+Q_DECLARE_METATYPE(CompleteFunctionCall)
+
 // -----------------------
 // QmlJSAssistProposalItem
 // -----------------------
@@ -338,12 +356,21 @@ void QmlJSAssistProposalItem::applyContextualContent(TextEditor::BaseTextEditor
     editor->setCursorPosition(basePosition);
     editor->remove(currentPosition - basePosition);
 
-    QString replaceable;
-    const QString &content = text();
-    if (content.endsWith(QLatin1String(": ")))
-        replaceable = QLatin1String(": ");
-    else if (content.endsWith(QLatin1Char('.')))
-        replaceable = QLatin1String(".");
+    QString content = text();
+    int cursorOffset = 0;
+
+    const CompletionSettings &completionSettings =
+            TextEditorSettings::instance()->completionSettings();
+    const bool autoInsertBrackets = completionSettings.m_autoInsertBrackets;
+
+    if (autoInsertBrackets && data().canConvert<CompleteFunctionCall>()) {
+        CompleteFunctionCall function = data().value<CompleteFunctionCall>();
+        content += QLatin1String("()");
+        if (function.hasArguments)
+            cursorOffset = -1;
+    }
+
+    QString replaceable = content;
     int replacedLength = 0;
     for (int i = 0; i < replaceable.length(); ++i) {
         const QChar a = replaceable.at(i);
@@ -355,6 +382,8 @@ void QmlJSAssistProposalItem::applyContextualContent(TextEditor::BaseTextEditor
     }
     const int length = editor->position() - basePosition + replacedLength;
     editor->replace(length, content);
+    if (cursorOffset)
+        editor->setCursorPosition(editor->position() + cursorOffset);
 }
 
 // -------------------------
@@ -363,10 +392,12 @@ void QmlJSAssistProposalItem::applyContextualContent(TextEditor::BaseTextEditor
 class FunctionHintProposalModel : public TextEditor::IFunctionHintProposalModel
 {
 public:
-    FunctionHintProposalModel(const QString &functionName, const QStringList &signature)
+    FunctionHintProposalModel(const QString &functionName, const QStringList &namedArguments,
+                              int optionalNamedArguments, bool isVariadic)
         : m_functionName(functionName)
-        , m_signature(signature)
-        , m_minimumArgumentCount(signature.size())
+        , m_namedArguments(namedArguments)
+        , m_optionalNamedArguments(optionalNamedArguments)
+        , m_isVariadic(isVariadic)
     {}
 
     virtual void reset() {}
@@ -376,8 +407,9 @@ public:
 
 private:
     QString m_functionName;
-    QStringList m_signature;
-    int m_minimumArgumentCount;
+    QStringList m_namedArguments;
+    int m_optionalNamedArguments;
+    bool m_isVariadic;
 };
 
 QString FunctionHintProposalModel::text(int index) const
@@ -388,11 +420,13 @@ QString FunctionHintProposalModel::text(int index) const
     prettyMethod += QString::fromLatin1("function ");
     prettyMethod += m_functionName;
     prettyMethod += QLatin1Char('(');
-    for (int i = 0; i < m_minimumArgumentCount; ++i) {
+    for (int i = 0; i < m_namedArguments.size(); ++i) {
+        if (i == m_namedArguments.size() - m_optionalNamedArguments)
+            prettyMethod += QLatin1Char('[');
         if (i != 0)
             prettyMethod += QLatin1String(", ");
 
-        QString arg = m_signature.at(i);
+        QString arg = m_namedArguments.at(i);
         if (arg.isEmpty()) {
             arg = QLatin1String("arg");
             arg += QString::number(i + 1);
@@ -400,6 +434,13 @@ QString FunctionHintProposalModel::text(int index) const
 
         prettyMethod += arg;
     }
+    if (m_isVariadic) {
+        if (m_namedArguments.size())
+            prettyMethod += QLatin1String(", ");
+        prettyMethod += QLatin1String("...");
+    }
+    if (m_optionalNamedArguments)
+        prettyMethod += QLatin1Char(']');
     prettyMethod += QLatin1Char(')');
     return prettyMethod;
 }
@@ -472,10 +513,12 @@ IAssistProposal *QmlJSCompletionAssistProcessor::createContentProposal() const
     return proposal;
 }
 
-IAssistProposal *QmlJSCompletionAssistProcessor::createHintProposal(const QString &functionName,
-                                                                    const QStringList &signature) const
+IAssistProposal *QmlJSCompletionAssistProcessor::createHintProposal(
+        const QString &functionName, const QStringList &namedArguments,
+        int optionalNamedArguments, bool isVariadic) const
 {
-    IFunctionHintProposalModel *model = new FunctionHintProposalModel(functionName, signature);
+    IFunctionHintProposalModel *model = new FunctionHintProposalModel(
+                functionName, namedArguments, optionalNamedArguments, isVariadic);
     IAssistProposal *proposal = new FunctionHintProposal(m_startPosition, model);
     return proposal;
 }
@@ -642,11 +685,12 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
                     if (indexOfDot != -1)
                         functionName = functionName.mid(indexOfDot + 1);
 
-                    QStringList signature;
-                    for (int i = 0; i < f->argumentCount(); ++i)
-                        signature.append(f->argumentName(i));
+                    QStringList namedArguments;
+                    for (int i = 0; i < f->namedArgumentCount(); ++i)
+                        namedArguments.append(f->argumentName(i));
 
-                    return createHintProposal(functionName.trimmed(), signature);
+                    return createHintProposal(functionName.trimmed(), namedArguments,
+                                              f->optionalNamedArgumentCount(), f->isVariadic());
                 }
             }
         }
diff --git a/src/plugins/qmljseditor/qmljscompletionassist.h b/src/plugins/qmljseditor/qmljscompletionassist.h
index a7227f0829e710a3ee33a10b14c396017f1a78cf..f31dddaa03903db53d3a7233ca6aee1768a3534e 100644
--- a/src/plugins/qmljseditor/qmljscompletionassist.h
+++ b/src/plugins/qmljseditor/qmljscompletionassist.h
@@ -99,8 +99,9 @@ public:
 
 private:
     TextEditor::IAssistProposal *createContentProposal() const;
-    TextEditor::IAssistProposal *createHintProposal(const QString &functionName,
-                                                    const QStringList &signature) const;
+    TextEditor::IAssistProposal *createHintProposal(
+            const QString &functionName, const QStringList &namedArguments,
+            int optionalNamedArguments, bool isVariadic) const;
 
     bool acceptsIdleEditor() const;