From 2512a684d5f41d1b679f840a90862b48c72599f1 Mon Sep 17 00:00:00 2001 From: Roberto Raggi <roberto.raggi@nokia.com> Date: Tue, 26 Jan 2010 10:50:30 +0100 Subject: [PATCH] Show the argument names from the method's signature. --- src/libs/qmljs/qmljsinterpreter.cpp | 134 ++++++++++++++---- src/libs/qmljs/qmljsinterpreter.h | 4 + src/plugins/qmljseditor/qmlcodecompletion.cpp | 29 +++- 3 files changed, 136 insertions(+), 31 deletions(-) diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index 65b311bf40c..78efcf634da 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -47,11 +47,58 @@ namespace { #ifndef NO_DECLARATIVE_BACKEND +class MetaFunction: public FunctionValue +{ + QMetaMethod _method; + +public: + MetaFunction(const QMetaMethod &method, Engine *engine) + : FunctionValue(engine), _method(method) + { + engine->registerObject(this); + } + + virtual const Value *returnValue() const + { + return engine()->undefinedValue(); + } + + virtual int argumentCount() const + { + return _method.parameterNames().size(); + } + + virtual const Value *argument(int) const + { + return engine()->undefinedValue(); + } + + virtual QString argumentName(int index) const + { + if (index < _method.parameterNames().size()) + return _method.parameterNames().at(index); + + return FunctionValue::argumentName(index); + } + + virtual bool isVariadic() const + { + return false; + } + + virtual const Value *invoke(const Activation *) const + { + return engine()->undefinedValue(); + } +}; + class QmlObjectValue: public ObjectValue { public: QmlObjectValue(const QMetaObject *metaObject, Engine *engine) - : ObjectValue(engine), _metaObject(metaObject) {} + : ObjectValue(engine), _metaObject(metaObject) + { + } virtual ~QmlObjectValue() {} @@ -64,6 +111,28 @@ public: return propertyValue(prop); } + for (int index = 0; index < _metaObject->methodCount(); ++index) { + QMetaMethod method = _metaObject->method(index); + + const QString signature = QString::fromUtf8(method.signature()); + + const int indexOfParen = signature.indexOf(QLatin1Char('(')); + if (indexOfParen == -1) + continue; // skip it, invalid signature. + + const QString methodName = signature.left(indexOfParen); + + if (methodName != name) { + continue; + + } else if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) { + return new MetaFunction(method, engine()); + + } else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) { + return new MetaFunction(method, engine()); + } + } + return ObjectValue::lookupMember(name); } @@ -76,9 +145,9 @@ public: } for (int index = 0; index < _metaObject->methodCount(); ++index) { - QMetaMethod meth = _metaObject->method(index); + QMetaMethod method = _metaObject->method(index); - const QString signature = QString::fromUtf8(meth.signature()); + const QString signature = QString::fromUtf8(method.signature()); const int indexOfParen = signature.indexOf(QLatin1Char('(')); if (indexOfParen == -1) @@ -86,12 +155,12 @@ public: const QString methodName = signature.left(indexOfParen); - if (meth.methodType() == QMetaMethod::Slot && meth.access() == QMetaMethod::Public) { + if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) { processor->processSlot(methodName, engine()->undefinedValue()); - } else if (meth.methodType() == QMetaMethod::Signal && meth.access() != QMetaMethod::Private) { + } else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) { // process the signal - processor->processSignal(methodName, engine()->undefinedValue()); // ### FIXME: assign a decent type to the signal + processor->processSignal(methodName, engine()->undefinedValue()); QString slotName; slotName += QLatin1String("on"); @@ -99,7 +168,7 @@ public: slotName += methodName.midRef(1); // process the generated slot - processor->processGeneratedSlot(slotName, engine()->undefinedValue()); // ### FIXME: assign a decent type to the slot + processor->processGeneratedSlot(slotName, engine()->undefinedValue()); } } @@ -803,11 +872,36 @@ const Value *FunctionValue::call(const ObjectValue *thisObject, const ValueList return invoke(&activation); } +const Value *FunctionValue::returnValue() const +{ + return engine()->undefinedValue(); +} + int FunctionValue::argumentCount() const { return 0; } +const Value *FunctionValue::argument(int) const +{ + return engine()->undefinedValue(); +} + +QString FunctionValue::argumentName(int index) const +{ + return QString::fromLatin1("arg%1").arg(index); +} + +bool FunctionValue::isVariadic() const +{ + return true; +} + +const Value *FunctionValue::invoke(const Activation *activation) const +{ + return activation->thisObject(); // ### FIXME: it should return undefined +} + const FunctionValue *FunctionValue::asFunctionValue() const { return this; @@ -1202,6 +1296,11 @@ const ObjectValue *Engine::mathObject() const return _mathObject; } +void Engine::registerObject(ObjectValue *object) +{ + _objects.append(object); +} + const Value *Engine::convertToBoolean(const Value *value) { return _convertToNumber(value); // ### implement convert to bool @@ -1423,8 +1522,8 @@ void Engine::initializePrototypes() addFunction(_mathObject, "exp", numberValue(), 1); addFunction(_mathObject, "floor", numberValue(), 1); addFunction(_mathObject, "log", numberValue(), 1); - addFunction(_mathObject, "max", numberValue(), 1); - addFunction(_mathObject, "min", numberValue(), 1); + addFunction(_mathObject, "max", numberValue(), 0); + addFunction(_mathObject, "min", numberValue(), 0); addFunction(_mathObject, "pow", numberValue(), 2); addFunction(_mathObject, "random", numberValue(), 1); addFunction(_mathObject, "round", numberValue(), 1); @@ -1535,23 +1634,6 @@ ObjectValue *Engine::newQmlObject(const QString &name) #endif } - -const Value *FunctionValue::invoke(const Activation *activation) const -{ - return activation->thisObject(); // ### FIXME: it should return undefined -} - -const Value *FunctionValue::argument(int /*index*/) const -{ - return engine()->undefinedValue(); -} - -const Value *FunctionValue::returnValue() const -{ - return engine()->undefinedValue(); -} - - //////////////////////////////////////////////////////////////////////////////// // convert to number //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index 27a34806dd3..f5fb5699e23 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -295,6 +295,8 @@ public: virtual int argumentCount() const; virtual const Value *argument(int index) const; + virtual QString argumentName(int index) const; + virtual bool isVariadic() const; virtual const Value *invoke(const Activation *activation) const; @@ -444,6 +446,8 @@ public: ObjectValue *globalObject() const; const ObjectValue *mathObject() const; + void registerObject(ObjectValue *object); + // prototypes ObjectValue *objectPrototype() const; ObjectValue *functionPrototype() const; diff --git a/src/plugins/qmljseditor/qmlcodecompletion.cpp b/src/plugins/qmljseditor/qmlcodecompletion.cpp index 45bfbe866a2..a1be0e89ae8 100644 --- a/src/plugins/qmljseditor/qmlcodecompletion.cpp +++ b/src/plugins/qmljseditor/qmlcodecompletion.cpp @@ -487,7 +487,9 @@ class FunctionArgumentWidget : public QLabel { public: FunctionArgumentWidget(); - void showFunctionHint(const QString &functionName, int minimumArgumentCount, int startPosition); + void showFunctionHint(const QString &functionName, + const QStringList &signature, + int startPosition); protected: bool eventFilter(QObject *obj, QEvent *e); @@ -497,6 +499,7 @@ private: void updateHintText(); QString m_functionName; + QStringList m_signature; int m_minimumArgumentCount; int m_startpos; int m_currentarg; @@ -563,13 +566,14 @@ FunctionArgumentWidget::FunctionArgumentWidget(): qApp->installEventFilter(this); } -void FunctionArgumentWidget::showFunctionHint(const QString &functionName, int mininumArgumentCount, int startPosition) +void FunctionArgumentWidget::showFunctionHint(const QString &functionName, const QStringList &signature, int startPosition) { if (m_startpos == startPosition) return; m_functionName = functionName; - m_minimumArgumentCount = mininumArgumentCount; + m_signature = signature; + m_minimumArgumentCount = signature.size(); m_startpos = startPosition; m_current = 0; m_escapePressed = false; @@ -663,7 +667,17 @@ void FunctionArgumentWidget::updateHintText() QString prettyMethod; prettyMethod += QString::fromLatin1("function "); prettyMethod += m_functionName; - prettyMethod += QLatin1String("(arguments...)"); + prettyMethod += QLatin1Char('('); + for (int i = 0; i < m_minimumArgumentCount; ++i) { + if (i != 0) + prettyMethod += QLatin1String(", "); + + prettyMethod += QLatin1String("arg"); + + if (m_minimumArgumentCount != 1) + prettyMethod += QString::number(i + 1); + } + prettyMethod += QLatin1Char(')'); m_numberLabel->setText(prettyMethod); @@ -970,7 +984,12 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) if (!m_functionArgumentWidget) m_functionArgumentWidget = new QmlJSEditor::Internal::FunctionArgumentWidget; - m_functionArgumentWidget->showFunctionHint(functionName.trimmed(), f->argumentCount(), + QStringList signature; + for (int i = 0; i < f->argumentCount(); ++i) + signature.append(f->argumentName(i)); + + m_functionArgumentWidget->showFunctionHint(functionName.trimmed(), + signature, m_startPosition); } -- GitLab