aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs
diff options
context:
space:
mode:
authorChristian Kamm <[email protected]>2011-10-05 14:14:35 +0200
committerChristian Kamm <[email protected]>2011-10-12 10:29:27 +0200
commit010ce2d20dc8d776fad3062cf68ad2c3535c9d2b (patch)
treec68fff9977c4b23a413bf7b4e1b93b40f2cc27dc /src/libs
parent03689eeb5043dd8c49be87ec45b92a388232fdcf (diff)
QmlJS: Set correct scope in signal handlers.
This means the code model will now offer correct completion and highlighting for arguments of signals in their handlers, example: MouseArea { onClicked: { mou<complete> // now also completes 'mouse' } } Reviewed-by: Fawzi Mohamed Change-Id: I01838ef00e391b13e6e5a832c9ec3cd983689c5b Reviewed-on: http://codereview.qt-project.org/6147 Reviewed-by: Christian Kamm <[email protected]> Sanity-Review: Christian Kamm <[email protected]>
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/qmljs/qmljsinterpreter.cpp81
-rw-r--r--src/libs/qmljs/qmljsinterpreter.h7
-rw-r--r--src/libs/qmljs/qmljsscopebuilder.cpp36
-rw-r--r--src/libs/qmljs/qmljsscopechain.cpp6
-rw-r--r--src/libs/qmljs/qmljsscopechain.h1
-rw-r--r--src/libs/qmljs/qmljstypedescriptionreader.cpp4
-rw-r--r--src/libs/qmljs/qmljsvalueowner.cpp1
7 files changed, 108 insertions, 28 deletions
diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index fab7b6ef6aa..e062078b1ab 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -180,7 +180,18 @@ QmlObjectValue::QmlObjectValue(FakeMetaObject::ConstPtr metaObject, const QStrin
}
QmlObjectValue::~QmlObjectValue()
-{}
+{
+ delete _metaSignatures;
+ delete _signalScopes;
+}
+
+static QString generatedSlotName(const QString &base)
+{
+ QString slotName = QLatin1String("on");
+ slotName += base.at(0).toUpper();
+ slotName += base.midRef(1);
+ return slotName;
+}
void QmlObjectValue::processMembers(MemberProcessor *processor) const
{
@@ -226,11 +237,8 @@ void QmlObjectValue::processMembers(MemberProcessor *processor) const
processor->processSignal(methodName, signature);
explicitSignals.insert(methodName);
- QString slotName = QLatin1String("on");
- slotName += methodName.at(0).toUpper();
- slotName += methodName.midRef(1);
-
// process the generated slot
+ const QString &slotName = generatedSlotName(methodName);
processor->processGeneratedSlot(slotName, signature);
}
}
@@ -242,18 +250,15 @@ void QmlObjectValue::processMembers(MemberProcessor *processor) const
continue;
const QString propertyName = prop.name();
- processor->processProperty(propertyName, propertyValue(prop));
+ processor->processProperty(propertyName, valueForCppName(prop.typeName()));
// every property always has a onXyzChanged slot, even if the NOTIFY
// signal has a different name
QString signalName = propertyName;
signalName += QLatin1String("Changed");
if (!explicitSignals.contains(signalName)) {
- QString slotName = QLatin1String("on");
- slotName += signalName.at(0).toUpper();
- slotName += signalName.midRef(1);
-
// process the generated slot
+ const QString &slotName = generatedSlotName(signalName);
processor->processGeneratedSlot(slotName, valueOwner()->undefinedValue());
}
}
@@ -264,9 +269,8 @@ void QmlObjectValue::processMembers(MemberProcessor *processor) const
ObjectValue::processMembers(processor);
}
-const Value *QmlObjectValue::propertyValue(const FakeMetaProperty &prop) const
+const Value *QmlObjectValue::valueForCppName(const QString &typeName) const
{
- QString typeName = prop.typeName();
const CppQmlTypes &cppTypes = valueOwner()->cppQmlTypes();
// check in the same package/version first
@@ -322,10 +326,9 @@ const Value *QmlObjectValue::propertyValue(const FakeMetaProperty &prop) const
const QStringList components = typeName.split(QLatin1String("::"));
if (components.size() == 2) {
base = valueOwner()->cppQmlTypes().objectByCppName(components.first());
- typeName = components.last();
}
if (base) {
- if (const QmlEnumValue *value = base->getEnumValue(typeName))
+ if (const QmlEnumValue *value = base->getEnumValue(components.last()))
return value;
}
@@ -419,6 +422,41 @@ const QmlEnumValue *QmlObjectValue::getEnumValue(const QString &typeName, const
return 0;
}
+const ObjectValue *QmlObjectValue::signalScope(const QString &signalName) const
+{
+ QHash<QString, const ObjectValue *> *scopes = _signalScopes;
+ if (!scopes) {
+ scopes = new QHash<QString, const ObjectValue *>;
+ // usually not all methods are signals
+ scopes->reserve(_metaObject->methodCount() / 2);
+ for (int index = 0; index < _metaObject->methodCount(); ++index) {
+ const FakeMetaMethod &method = _metaObject->method(index);
+ if (method.methodType() != FakeMetaMethod::Signal || method.access() == FakeMetaMethod::Private)
+ continue;
+
+ const QStringList &parameterNames = method.parameterNames();
+ const QStringList &parameterTypes = method.parameterTypes();
+ QTC_ASSERT(parameterNames.size() == parameterTypes.size(), continue);
+
+ ObjectValue *scope = valueOwner()->newObject(/*prototype=*/0);
+ for (int i = 0; i < parameterNames.size(); ++i) {
+ const QString &name = parameterNames.at(i);
+ const QString &type = parameterTypes.at(i);
+ if (name.isEmpty())
+ continue;
+ scope->setMember(name, valueForCppName(type));
+ }
+ scopes->insert(generatedSlotName(method.methodName()), scope);
+ }
+ if (!_signalScopes.testAndSetOrdered(0, scopes)) {
+ delete _signalScopes;
+ scopes = _signalScopes;
+ }
+ }
+
+ return scopes->value(signalName);
+}
+
bool QmlObjectValue::isWritable(const QString &propertyName) const
{
for (const QmlObjectValue *it = this; it; it = it->prototype()) {
@@ -1832,9 +1870,7 @@ ASTPropertyReference::ASTPropertyReference(UiPublicMember *ast, const Document *
: Reference(valueOwner), _ast(ast), _doc(doc)
{
const QString &propertyName = ast->name.toString();
- _onChangedSlotName = QLatin1String("on");
- _onChangedSlotName += propertyName.at(0).toUpper();
- _onChangedSlotName += propertyName.midRef(1);
+ _onChangedSlotName = generatedSlotName(propertyName);
_onChangedSlotName += QLatin1String("Changed");
}
@@ -1882,9 +1918,14 @@ ASTSignal::ASTSignal(UiPublicMember *ast, const Document *doc, ValueOwner *value
: FunctionValue(valueOwner), _ast(ast), _doc(doc)
{
const QString &signalName = ast->name.toString();
- _slotName = QLatin1String("on");
- _slotName += signalName.at(0).toUpper();
- _slotName += signalName.midRef(1);
+ _slotName = generatedSlotName(signalName);
+
+ ObjectValue *v = valueOwner->newObject(/*prototype=*/0);
+ for (UiParameterList *it = ast->parameters; it; it = it->next) {
+ if (!it->name.isEmpty())
+ v->setMember(it->name.toString(), valueOwner->defaultValueForBuiltinType(it->type.toString()));
+ }
+ _bodyScope = v;
}
ASTSignal::~ASTSignal()
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index 6bc65a946e3..56268a127f2 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -424,7 +424,7 @@ public:
virtual ~QmlObjectValue();
virtual void processMembers(MemberProcessor *processor) const;
- const Value *propertyValue(const LanguageUtils::FakeMetaProperty &prop) const;
+ const Value *valueForCppName(const QString &typeName) const;
using ObjectValue::prototype;
const QmlObjectValue *prototype() const;
@@ -448,6 +448,8 @@ public:
LanguageUtils::FakeMetaEnum getEnum(const QString &typeName, const QmlObjectValue **foundInScope = 0) const;
const QmlEnumValue *getEnumValue(const QString &typeName, const QmlObjectValue **foundInScope = 0) const;
+
+ const ObjectValue *signalScope(const QString &signalName) const;
protected:
bool isDerivedFrom(LanguageUtils::FakeMetaObject::ConstPtr base) const;
@@ -461,6 +463,7 @@ private:
const LanguageUtils::ComponentVersion _componentVersion;
const LanguageUtils::ComponentVersion _importVersion;
mutable QAtomicPointer< QList<const Value *> > _metaSignatures;
+ mutable QAtomicPointer< QHash<QString, const ObjectValue *> > _signalScopes;
QHash<QString, const QmlEnumValue * > _enums;
int _metaObjectRevision;
};
@@ -766,6 +769,7 @@ class QMLJS_EXPORT ASTSignal: public FunctionValue
AST::UiPublicMember *_ast;
const Document *_doc;
QString _slotName;
+ const ObjectValue *_bodyScope;
public:
ASTSignal(AST::UiPublicMember *ast, const Document *doc, ValueOwner *valueOwner);
@@ -773,6 +777,7 @@ public:
AST::UiPublicMember *ast() const { return _ast; }
QString slotName() const { return _slotName; }
+ const ObjectValue *bodyScope() const { return _bodyScope; }
// FunctionValue interface
virtual int argumentCount() const;
diff --git a/src/libs/qmljs/qmljsscopebuilder.cpp b/src/libs/qmljs/qmljsscopebuilder.cpp
index ed52edb6a80..fd72b565338 100644
--- a/src/libs/qmljs/qmljsscopebuilder.cpp
+++ b/src/libs/qmljs/qmljsscopebuilder.cpp
@@ -67,6 +67,35 @@ void ScopeBuilder::push(AST::Node *node)
setQmlScopeObject(qmlObject);
}
+ // JS signal handler scope
+ if (UiScriptBinding *script = cast<UiScriptBinding *>(node)) {
+ QString name;
+ if (script->qualifiedId)
+ name = script->qualifiedId->name.toString();
+ if (!_scopeChain->qmlScopeObjects().isEmpty()
+ && name.startsWith(QLatin1String("on"))
+ && !script->qualifiedId->next) {
+ const ObjectValue *owner = 0;
+ const Value *value = 0;
+ // try to find the name on the scope objects
+ foreach (const ObjectValue *scope, _scopeChain->qmlScopeObjects()) {
+ value = scope->lookupMember(name, _scopeChain->context(), &owner);
+ if (value)
+ break;
+ }
+ // signals defined in QML
+ if (const ASTSignal *astsig = dynamic_cast<const ASTSignal *>(value)) {
+ _scopeChain->appendJsScope(astsig->bodyScope());
+ }
+ // signals defined in C++
+ else if (const QmlObjectValue *qmlObject = dynamic_cast<const QmlObjectValue *>(owner)) {
+ if (const ObjectValue *scope = qmlObject->signalScope(name)) {
+ _scopeChain->appendJsScope(scope);
+ }
+ }
+ }
+ }
+
// JS scopes
switch (node->kind) {
case Node::Kind_UiScriptBinding:
@@ -75,11 +104,8 @@ void ScopeBuilder::push(AST::Node *node)
case Node::Kind_UiPublicMember:
{
ObjectValue *scope = _scopeChain->document()->bind()->findAttachedJSScope(node);
- if (scope) {
- QList<const ObjectValue *> jsScopes = _scopeChain->jsScopes();
- jsScopes += scope;
- _scopeChain->setJsScopes(jsScopes);
- }
+ if (scope)
+ _scopeChain->appendJsScope(scope);
break;
}
default:
diff --git a/src/libs/qmljs/qmljsscopechain.cpp b/src/libs/qmljs/qmljsscopechain.cpp
index 76016345b5e..8406be157d2 100644
--- a/src/libs/qmljs/qmljsscopechain.cpp
+++ b/src/libs/qmljs/qmljsscopechain.cpp
@@ -187,6 +187,12 @@ void ScopeChain::setJsScopes(const QList<const ObjectValue *> &jsScopes)
m_jsScopes = jsScopes;
}
+void ScopeChain::appendJsScope(const ObjectValue *scope)
+{
+ m_modified = true;
+ m_jsScopes += scope;
+}
+
QList<const ObjectValue *> ScopeChain::all() const
{
if (m_modified)
diff --git a/src/libs/qmljs/qmljsscopechain.h b/src/libs/qmljs/qmljsscopechain.h
index 6eb9e57f84e..1a16bb82a9c 100644
--- a/src/libs/qmljs/qmljsscopechain.h
+++ b/src/libs/qmljs/qmljsscopechain.h
@@ -100,6 +100,7 @@ public:
QList<const ObjectValue *> jsScopes() const;
void setJsScopes(const QList<const ObjectValue *> &jsScopes);
+ void appendJsScope(const ObjectValue *scope);
QList<const ObjectValue *> all() const;
diff --git a/src/libs/qmljs/qmljstypedescriptionreader.cpp b/src/libs/qmljs/qmljstypedescriptionreader.cpp
index 0410fee3117..e5695bfcd2a 100644
--- a/src/libs/qmljs/qmljstypedescriptionreader.cpp
+++ b/src/libs/qmljs/qmljstypedescriptionreader.cpp
@@ -350,9 +350,9 @@ void TypeDescriptionReader::readParameter(UiObjectDefinition *ast, FakeMetaMetho
continue;
}
- QString id = toString(script->qualifiedId);
+ const QString id = toString(script->qualifiedId);
if (id == "name") {
- id = readStringBinding(script);
+ name = readStringBinding(script);
} else if (id == "type") {
type = readStringBinding(script);
} else if (id == "isPointer") {
diff --git a/src/libs/qmljs/qmljsvalueowner.cpp b/src/libs/qmljs/qmljsvalueowner.cpp
index c2c6974fbff..a4b96bd40d2 100644
--- a/src/libs/qmljs/qmljsvalueowner.cpp
+++ b/src/libs/qmljs/qmljsvalueowner.cpp
@@ -932,6 +932,7 @@ const ObjectValue *ValueOwner::qmlVector3DObject()
const Value *ValueOwner::defaultValueForBuiltinType(const QString &name) const
{
+ // this list is defined in ProcessAST::visit(UiPublicMember) in qdeclarativescript.cpp
if (name == QLatin1String("int")) {
return intValue();
} else if (name == QLatin1String("bool")) {