summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Kamm <christian.d.kamm@nokia.com>2011-02-10 17:03:52 +0100
committerChristian Kamm <christian.d.kamm@nokia.com>2011-02-10 17:04:22 +0100
commit490f2797f636ff49ce0a778610a2532d1277e4d4 (patch)
tree4f8e00de7255515a15d031fce4e3aeceabfff8e7
parent187ae1e94a1b151c3d82cd47c51b73815df08d49 (diff)
downloadqt-creator-490f2797f636ff49ce0a778610a2532d1277e4d4.tar.gz
QmlJS: Completion for attached properties.
-rw-r--r--src/libs/qmljs/qmljscheck.cpp2
-rw-r--r--src/libs/qmljs/qmljsinterpreter.cpp92
-rw-r--r--src/libs/qmljs/qmljsinterpreter.h19
-rw-r--r--src/libs/qmljs/qmljsscopebuilder.cpp4
-rw-r--r--src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp2
-rw-r--r--src/plugins/qmljseditor/qmljscodecompletion.cpp19
-rw-r--r--src/plugins/qmljseditor/qmljsfindreferences.cpp2
7 files changed, 128 insertions, 12 deletions
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index 8c3d0d1554..ce0d97f5cb 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -826,7 +826,7 @@ const Value *Check::checkScopeObjectMember(const UiQualifiedId *id)
bool isAttachedProperty = false;
if (! propertyName.isEmpty() && propertyName[0].isUpper()) {
isAttachedProperty = true;
- if (const ObjectValue *qmlTypes = _context.scopeChain().qmlTypes)
+ if (const ObjectValue *qmlTypes = _context.scopeChain().qmlAttachedTypes)
scopeObjects += qmlTypes;
}
diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 8eee26d03d..90416d3a6d 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -588,6 +588,7 @@ private:
QmlObjectValue::QmlObjectValue(FakeMetaObject::ConstPtr metaObject, const QString &className,
const QString &packageName, const ComponentVersion version, Engine *engine)
: ObjectValue(engine),
+ _attachedType(0),
_metaObject(metaObject),
_packageName(packageName),
_componentVersion(version)
@@ -719,6 +720,16 @@ const QmlObjectValue *QmlObjectValue::prototype() const
return static_cast<const QmlObjectValue *>(_prototype);
}
+const QmlObjectValue *QmlObjectValue::attachedType() const
+{
+ return _attachedType;
+}
+
+void QmlObjectValue::setAttachedType(QmlObjectValue *value)
+{
+ _attachedType = value;
+}
+
FakeMetaObject::ConstPtr QmlObjectValue::metaObject() const
{
return _metaObject;
@@ -1294,6 +1305,7 @@ void StringValue::accept(ValueVisitor *visitor) const
ScopeChain::ScopeChain()
: globalScope(0)
, qmlTypes(0)
+ , qmlAttachedTypes(0)
{
}
@@ -1353,8 +1365,9 @@ void ScopeChain::update()
_all += qmlScopeObjects;
if (ids)
_all += ids;
- if (qmlTypes)
- _all += qmlTypes;
+ if (qmlAttachedTypes)
+ _all += qmlAttachedTypes;
+ // qmlTypes are not added on purpose
_all += jsScopes;
}
@@ -2091,9 +2104,18 @@ QmlObjectValue *CppQmlTypes::makeObject(
void CppQmlTypes::setPrototypes(QmlObjectValue *object)
{
- if (!object || object->metaObject()->superclassName().isEmpty())
+ if (!object)
return;
+ FakeMetaObject::ConstPtr fmo = object->metaObject();
+
+ // resolve attached type
+ if (!fmo->attachedTypeName().isEmpty()) {
+ QmlObjectValue *attachedObject = typeByCppName(fmo->attachedTypeName());
+ if (attachedObject)
+ object->setAttachedType(attachedObject);
+ }
+
const QString targetPackage = object->packageName();
// set prototypes for whole chain, creating new QmlObjectValues if necessary
@@ -2101,7 +2123,6 @@ void CppQmlTypes::setPrototypes(QmlObjectValue *object)
// Example: QObject (Qt, QtQuick) -> Positioner (not exported) -> Column (Qt, QtQuick)
// needs to create Positioner (Qt) and Positioner (QtQuick)
QmlObjectValue *v = object;
- FakeMetaObject::ConstPtr fmo = v->metaObject();
while (!v->prototype() && !fmo->superclassName().isEmpty()) {
QmlObjectValue *superValue = getOrCreate(targetPackage, fmo->superclassName());
if (!superValue)
@@ -3404,3 +3425,66 @@ ImportInfo TypeEnvironment::importInfo(const QString &name, const Context *conte
}
return ImportInfo();
}
+
+namespace {
+class AttachedTypeProcessor: public MemberProcessor
+{
+ MemberProcessor *_wrapped;
+
+public:
+ AttachedTypeProcessor(MemberProcessor *wrapped) : _wrapped(wrapped) {}
+
+ static const QmlObjectValue *attachedType(const Value *v)
+ {
+ if (const QmlObjectValue *qmlValue = dynamic_cast<const QmlObjectValue *>(v)) {
+ return qmlValue->attachedType();
+ }
+ return 0;
+ }
+
+ virtual bool processProperty(const QString &name, const Value *value)
+ {
+ const QmlObjectValue *qmlValue = attachedType(value);
+ return qmlValue ? _wrapped->processProperty(name, qmlValue) : true;
+ }
+ virtual bool processEnumerator(const QString &name, const Value *value)
+ {
+ const QmlObjectValue *qmlValue = attachedType(value);
+ return qmlValue ? _wrapped->processEnumerator(name, qmlValue) : true;
+ }
+ virtual bool processSignal(const QString &name, const Value *value)
+ {
+ const QmlObjectValue *qmlValue = attachedType(value);
+ return qmlValue ? _wrapped->processSignal(name, qmlValue) : true;
+ }
+ virtual bool processSlot(const QString &name, const Value *value)
+ {
+ const QmlObjectValue *qmlValue = attachedType(value);
+ return qmlValue ? _wrapped->processSlot(name, qmlValue) : true;
+ }
+ virtual bool processGeneratedSlot(const QString &name, const Value *value)
+ {
+ const QmlObjectValue *qmlValue = attachedType(value);
+ return qmlValue ? _wrapped->processGeneratedSlot(name, qmlValue) : true;
+ }
+};
+} // anonymous namespace
+
+AttachedTypeEnvironment::AttachedTypeEnvironment(const TypeEnvironment *typeEnv)
+ : ObjectValue(typeEnv->engine())
+ , _typeEnvironment(typeEnv)
+{
+}
+
+const Value *AttachedTypeEnvironment::lookupMember(const QString &name, const Context *context,
+ const ObjectValue **, bool) const
+{
+ const Value *v = _typeEnvironment->lookupMember(name, context);
+ return AttachedTypeProcessor::attachedType(v);
+}
+
+void AttachedTypeEnvironment::processMembers(MemberProcessor *processor) const
+{
+ AttachedTypeProcessor wrappedProcessor(processor);
+ _typeEnvironment->processMembers(&wrappedProcessor);
+}
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index 7c7a52a344..c03c97a10a 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -73,6 +73,7 @@ class Reference;
class ColorValue;
class AnchorLineValue;
class TypeEnvironment;
+class AttachedTypeEnvironment;
typedef QList<const Value *> ValueList;
@@ -304,6 +305,7 @@ public:
QSharedPointer<const QmlComponentChain> qmlComponentScope;
QList<const ObjectValue *> qmlScopeObjects;
const TypeEnvironment *qmlTypes;
+ const AttachedTypeEnvironment *qmlAttachedTypes;
QList<const ObjectValue *> jsScopes;
// rebuilds the flat list of all scopes
@@ -461,6 +463,9 @@ public:
using ObjectValue::prototype;
const QmlObjectValue *prototype() const;
+ const QmlObjectValue *attachedType() const;
+ void setAttachedType(QmlObjectValue *value);
+
LanguageUtils::FakeMetaObject::ConstPtr metaObject() const;
QString packageName() const;
@@ -484,6 +489,7 @@ protected:
bool isDerivedFrom(LanguageUtils::FakeMetaObject::ConstPtr base) const;
private:
+ QmlObjectValue *_attachedType;
LanguageUtils::FakeMetaObject::ConstPtr _metaObject;
const QString _packageName;
const LanguageUtils::ComponentVersion _componentVersion;
@@ -1032,6 +1038,19 @@ public:
ImportInfo importInfo(const QString &name, const Context *context) const;
};
+class QMLJS_EXPORT AttachedTypeEnvironment: public ObjectValue
+{
+ const TypeEnvironment *_typeEnvironment;
+
+public:
+ AttachedTypeEnvironment(const TypeEnvironment *typeEnv);
+
+ virtual const Value *lookupMember(const QString &name, const Context *context,
+ const ObjectValue **foundInObject = 0,
+ bool examinePrototypes = true) const;
+ virtual void processMembers(MemberProcessor *processor) const;
+};
+
} } // namespace QmlJS::Interpreter
#endif // QMLJS_INTERPRETER_H
diff --git a/src/libs/qmljs/qmljsscopebuilder.cpp b/src/libs/qmljs/qmljsscopebuilder.cpp
index 166361bfec..fc5e2a9bd6 100644
--- a/src/libs/qmljs/qmljsscopebuilder.cpp
+++ b/src/libs/qmljs/qmljsscopebuilder.cpp
@@ -129,8 +129,10 @@ void ScopeBuilder::initializeScopeChain()
componentScopes.insert(_doc.data(), chain);
makeComponentChain(_doc, chain, &componentScopes);
- if (const TypeEnvironment *typeEnvironment = _context->typeEnvironment(_doc.data()))
+ if (const TypeEnvironment *typeEnvironment = _context->typeEnvironment(_doc.data())) {
scopeChain.qmlTypes = typeEnvironment;
+ scopeChain.qmlAttachedTypes = new AttachedTypeEnvironment(typeEnvironment);
+ }
} else {
// add scope chains for all components that import this file
foreach (Document::Ptr otherDoc, _snapshot) {
diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
index 39c3d9c33b..f967c97da0 100644
--- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
+++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
@@ -308,7 +308,7 @@ public:
bool isAttachedProperty = false;
if (! propertyName.isEmpty() && propertyName[0].isUpper()) {
isAttachedProperty = true;
- if (const Interpreter::ObjectValue *qmlTypes = m_context->scopeChain().qmlTypes)
+ if (const Interpreter::ObjectValue *qmlTypes = m_context->scopeChain().qmlAttachedTypes)
scopeObjects += qmlTypes;
}
diff --git a/src/plugins/qmljseditor/qmljscodecompletion.cpp b/src/plugins/qmljseditor/qmljscodecompletion.cpp
index 88a7c81206..051debcb69 100644
--- a/src/plugins/qmljseditor/qmljscodecompletion.cpp
+++ b/src/plugins/qmljseditor/qmljscodecompletion.cpp
@@ -841,10 +841,12 @@ int CodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
bool doGlobalCompletion = true;
bool doQmlKeywordCompletion = true;
bool doJsKeywordCompletion = true;
+ bool doQmlTypeCompletion = false;
if (contextFinder.isInLhsOfBinding() && qmlScopeType) {
doGlobalCompletion = false;
doJsKeywordCompletion = false;
+ doQmlTypeCompletion = true;
EnumerateProperties enumerateProperties(context);
enumerateProperties.setGlobalCompletion(true);
@@ -858,8 +860,6 @@ int CodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
m_completions.append(idPropertyCompletion);
addCompletionsPropertyLhs(enumerateProperties(qmlScopeType), symbolIcon, PropertyOrder, contextFinder.isAfterOnInLhsOfBinding());
- if (const Interpreter::ObjectValue *qmlTypes = context->scopeChain().qmlTypes)
- addCompletions(enumerateProperties(qmlTypes), symbolIcon, TypeOrder);
if (ScopeBuilder::isPropertyChangesObject(context, qmlScopeType)
&& context->scopeChain().qmlScopeObjects.size() == 2) {
@@ -884,6 +884,16 @@ int CodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
}
}
+ if (!contextFinder.isInImport() && !contextFinder.isInQmlContext())
+ doQmlTypeCompletion = true;
+
+ if (doQmlTypeCompletion) {
+ if (const Interpreter::ObjectValue *qmlTypes = context->scopeChain().qmlTypes) {
+ EnumerateProperties enumerateProperties(context);
+ addCompletions(enumerateProperties(qmlTypes), symbolIcon, TypeOrder);
+ }
+ }
+
if (doGlobalCompletion) {
// It's a global completion.
EnumerateProperties enumerateProperties(context);
@@ -934,9 +944,10 @@ int CodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
if (value && completionOperator == QLatin1Char('.')) { // member completion
EnumerateProperties enumerateProperties(context);
- if (contextFinder.isInLhsOfBinding() && qmlScopeType && expressionUnderCursor.text().at(0).isLower())
+ if (contextFinder.isInLhsOfBinding() && qmlScopeType) {
+ enumerateProperties.setEnumerateGeneratedSlots(true);
addCompletionsPropertyLhs(enumerateProperties(value), symbolIcon, PropertyOrder, contextFinder.isAfterOnInLhsOfBinding());
- else
+ } else
addCompletions(enumerateProperties(value), symbolIcon, SymbolOrder);
} else if (value && completionOperator == QLatin1Char('(') && m_startPosition == editor->position()) {
// function completion
diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp
index a92bcbacdb..779e3222d1 100644
--- a/src/plugins/qmljseditor/qmljsfindreferences.cpp
+++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp
@@ -178,7 +178,7 @@ protected:
const ScopeChain &chain = _context->scopeChain();
if (chain.jsScopes.contains(scope)
|| chain.qmlScopeObjects.contains(scope)
- || chain.qmlTypes == scope
+ || chain.qmlAttachedTypes == scope
|| chain.globalScope == scope)
return false;