QmlJS: Find setContextProperty calls in C++ and expose to QML.

Task-number: QTCREATORBUG-3199

Change-Id: I591490ceafadc0f5a07c63ec063f1bdfa7055f47
Reviewed-on: http://codereview.qt-project.org/4074
Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
This commit is contained in:
Christian Kamm
2011-08-25 12:35:55 +02:00
parent c2f31f16dc
commit 10a956a8f7
8 changed files with 327 additions and 71 deletions

View File

@@ -256,7 +256,8 @@ Document::Document(const QString &fileName)
: _fileName(QDir::cleanPath(fileName)), : _fileName(QDir::cleanPath(fileName)),
_globalNamespace(0), _globalNamespace(0),
_revision(0), _revision(0),
_editorRevision(0) _editorRevision(0),
_checkMode(0)
{ {
_control = new Control(); _control = new Control();
@@ -569,6 +570,8 @@ void Document::check(CheckMode mode)
{ {
Q_ASSERT(!_globalNamespace); Q_ASSERT(!_globalNamespace);
_checkMode = mode;
if (! isParsed()) if (! isParsed())
parse(); parse();

View File

@@ -120,6 +120,7 @@ public:
bool parse(ParseMode mode = ParseTranlationUnit); bool parse(ParseMode mode = ParseTranlationUnit);
enum CheckMode { enum CheckMode {
Unchecked,
FullCheck, FullCheck,
FastCheck FastCheck
}; };
@@ -322,6 +323,9 @@ public:
void keepSourceAndAST(); void keepSourceAndAST();
void releaseSourceAndAST(); void releaseSourceAndAST();
CheckMode checkMode() const
{ return static_cast<CheckMode>(_checkMode); }
private: private:
QString _fileName; QString _fileName;
Control *_control; Control *_control;
@@ -338,6 +342,7 @@ private:
QAtomicInt _keepSourceAndASTCount; QAtomicInt _keepSourceAndASTCount;
unsigned _revision; unsigned _revision;
unsigned _editorRevision; unsigned _editorRevision;
quint8 _checkMode;
friend class Snapshot; friend class Snapshot;
}; };

View File

@@ -120,11 +120,29 @@ Link::Link(const Snapshot &snapshot, const QStringList &importPaths, const Libra
d->diagnosticMessages = 0; d->diagnosticMessages = 0;
d->allDiagnosticMessages = 0; d->allDiagnosticMessages = 0;
// populate engine with types from C++
ModelManagerInterface *modelManager = ModelManagerInterface::instance(); ModelManagerInterface *modelManager = ModelManagerInterface::instance();
if (modelManager) { if (modelManager) {
foreach (const QList<FakeMetaObject::ConstPtr> &cppTypes, modelManager->cppQmlTypes()) { ModelManagerInterface::CppDataHash cppDataHash = modelManager->cppData();
d->valueOwner->cppQmlTypes().load(d->valueOwner, cppTypes);
// populate engine with types from C++
foreach (const ModelManagerInterface::CppData &cppData, cppDataHash) {
d->valueOwner->cppQmlTypes().load(d->valueOwner, cppData.exportedTypes);
}
// populate global object with context properties from C++
ObjectValue *global = d->valueOwner->globalObject();
foreach (const ModelManagerInterface::CppData &cppData, cppDataHash) {
QMapIterator<QString, QString> it(cppData.contextProperties);
while (it.hasNext()) {
it.next();
const Value *value = 0;
const QString cppTypeName = it.value();
if (!cppTypeName.isEmpty())
value = d->valueOwner->cppQmlTypes().typeByCppName(cppTypeName);
if (!value)
value = d->valueOwner->undefinedValue();
global->setMember(it.key(), value);
}
} }
} }
} }

View File

@@ -110,7 +110,14 @@ public:
Table _elements; Table _elements;
}; };
typedef QHash<QString, QList<LanguageUtils::FakeMetaObject::ConstPtr> > CppQmlTypeHash; class CppData
{
public:
QList<LanguageUtils::FakeMetaObject::ConstPtr> exportedTypes;
QMap<QString, QString> contextProperties;
};
typedef QHash<QString, CppData> CppDataHash;
public: public:
ModelManagerInterface(QObject *parent = 0); ModelManagerInterface(QObject *parent = 0);
@@ -138,7 +145,7 @@ public:
virtual void loadPluginTypes(const QString &libraryPath, const QString &importPath, virtual void loadPluginTypes(const QString &libraryPath, const QString &importPath,
const QString &importUri, const QString &importVersion) = 0; const QString &importUri, const QString &importVersion) = 0;
virtual CppQmlTypeHash cppQmlTypes() const = 0; virtual CppDataHash cppData() const = 0;
virtual LibraryInfo builtins(const Document::Ptr &doc) const = 0; virtual LibraryInfo builtins(const Document::Ptr &doc) const = 0;

View File

@@ -64,10 +64,18 @@ public:
QString typeExpression; QString typeExpression;
}; };
class ContextProperty {
public:
QString name;
QString expression;
unsigned line, column;
};
class FindExportsVisitor : protected ASTVisitor class FindExportsVisitor : protected ASTVisitor
{ {
CPlusPlus::Document::Ptr _doc; CPlusPlus::Document::Ptr _doc;
QList<ExportedQmlType> _exportedTypes; QList<ExportedQmlType> _exportedTypes;
QList<ContextProperty> _contextProperties;
CompoundStatementAST *_compound; CompoundStatementAST *_compound;
ASTMatcher _matcher; ASTMatcher _matcher;
ASTPatternBuilder _builder; ASTPatternBuilder _builder;
@@ -81,11 +89,11 @@ public:
, _compound(0) , _compound(0)
{} {}
QList<ExportedQmlType> operator()() void operator()()
{ {
_exportedTypes.clear(); _exportedTypes.clear();
_contextProperties.clear();
accept(translationUnit()->ast()); accept(translationUnit()->ast());
return _exportedTypes;
} }
QList<Document::DiagnosticMessage> messages() const QList<Document::DiagnosticMessage> messages() const
@@ -93,6 +101,16 @@ public:
return _messages; return _messages;
} }
QList<ExportedQmlType> exportedTypes() const
{
return _exportedTypes;
}
QList<ContextProperty> contextProperties() const
{
return _contextProperties;
}
protected: protected:
virtual bool visit(CompoundStatementAST *ast) virtual bool visit(CompoundStatementAST *ast)
{ {
@@ -104,6 +122,14 @@ protected:
} }
virtual bool visit(CallAST *ast) virtual bool visit(CallAST *ast)
{
if (checkForQmlRegisterType(ast))
return false;
checkForSetContextProperty(ast);
return false;
}
bool checkForQmlRegisterType(CallAST *ast)
{ {
IdExpressionAST *idExp = ast->base_expression->asIdExpression(); IdExpressionAST *idExp = ast->base_expression->asIdExpression();
if (!idExp || !idExp->name) if (!idExp || !idExp->name)
@@ -139,7 +165,7 @@ protected:
// last argument must be a string literal // last argument must be a string literal
const StringLiteral *nameLit = 0; const StringLiteral *nameLit = 0;
if (StringLiteralAST *nameAst = ast->expression_list->next->next->next->value->asStringLiteral()) if (StringLiteralAST *nameAst = skipStringCall(ast->expression_list->next->next->next->value)->asStringLiteral())
nameLit = translationUnit()->stringLiteral(nameAst->literal_token); nameLit = translationUnit()->stringLiteral(nameAst->literal_token);
if (!nameLit) { if (!nameLit) {
unsigned line, column; unsigned line, column;
@@ -155,7 +181,7 @@ protected:
// if the first argument is a string literal, things are easy // if the first argument is a string literal, things are easy
QString packageName; QString packageName;
if (StringLiteralAST *packageAst = ast->expression_list->value->asStringLiteral()) { if (StringLiteralAST *packageAst = skipStringCall(ast->expression_list->value)->asStringLiteral()) {
const StringLiteral *packageLit = translationUnit()->stringLiteral(packageAst->literal_token); const StringLiteral *packageLit = translationUnit()->stringLiteral(packageAst->literal_token);
packageName = QString::fromUtf8(packageLit->chars(), packageLit->size()); packageName = QString::fromUtf8(packageLit->chars(), packageLit->size());
} }
@@ -242,7 +268,118 @@ protected:
_exportedTypes += exportedType; _exportedTypes += exportedType;
return false; return true;
}
static NameAST *callName(ExpressionAST *exp)
{
if (IdExpressionAST *idExp = exp->asIdExpression())
return idExp->name;
if (MemberAccessAST *memberExp = exp->asMemberAccess())
return memberExp->member_name;
return 0;
}
static ExpressionAST *skipQVariant(ExpressionAST *ast, TranslationUnit *translationUnit)
{
CallAST *call = ast->asCall();
if (!call)
return ast;
if (!call->expression_list
|| !call->expression_list->value
|| call->expression_list->next)
return ast;
IdExpressionAST *idExp = call->base_expression->asIdExpression();
if (!idExp || !idExp->name)
return ast;
// QVariant(foo) -> foo
if (SimpleNameAST *simpleName = idExp->name->asSimpleName()) {
const Identifier *id = translationUnit->identifier(simpleName->identifier_token);
if (!id)
return ast;
if (QString::fromUtf8(id->chars(), id->size()) != QLatin1String("QVariant"))
return ast;
return call->expression_list->value;
}
// QVariant::fromValue(foo) -> foo
else if (QualifiedNameAST *q = idExp->name->asQualifiedName()) {
SimpleNameAST *simpleRhsName = q->unqualified_name->asSimpleName();
if (!simpleRhsName
|| !q->nested_name_specifier_list
|| !q->nested_name_specifier_list->value
|| q->nested_name_specifier_list->next)
return ast;
const Identifier *rhsId = translationUnit->identifier(simpleRhsName->identifier_token);
if (!rhsId)
return ast;
if (QString::fromUtf8(rhsId->chars(), rhsId->size()) != QLatin1String("fromValue"))
return ast;
NestedNameSpecifierAST *nested = q->nested_name_specifier_list->value;
SimpleNameAST *simpleLhsName = nested->class_or_namespace_name->asSimpleName();
if (!simpleLhsName)
return ast;
const Identifier *lhsId = translationUnit->identifier(simpleLhsName->identifier_token);
if (!lhsId)
return ast;
if (QString::fromUtf8(lhsId->chars(), lhsId->size()) != QLatin1String("QVariant"))
return ast;
return call->expression_list->value;
}
return ast;
}
bool checkForSetContextProperty(CallAST *ast)
{
// check whether ast->base_expression has the 'setContextProperty' name
NameAST *callNameAst = callName(ast->base_expression);
if (!callNameAst)
return false;
SimpleNameAST *simpleNameAst = callNameAst->asSimpleName();
if (!simpleNameAst || !simpleNameAst->identifier_token)
return false;
const Identifier *nameIdentifier = translationUnit()->identifier(simpleNameAst->identifier_token);
if (!nameIdentifier)
return false;
const QString callName = QString::fromUtf8(nameIdentifier->chars(), nameIdentifier->size());
if (callName != QLatin1String("setContextProperty"))
return false;
// must have two arguments
if (!ast->expression_list
|| !ast->expression_list->value || !ast->expression_list->next
|| !ast->expression_list->next->value || ast->expression_list->next->next)
return false;
// first argument must be a string literal
const StringLiteral *nameLit = 0;
if (StringLiteralAST *nameAst = skipStringCall(ast->expression_list->value)->asStringLiteral())
nameLit = translationUnit()->stringLiteral(nameAst->literal_token);
if (!nameLit) {
unsigned line, column;
translationUnit()->getTokenStartPosition(ast->expression_list->value->firstToken(), &line, &column);
_messages += Document::DiagnosticMessage(
Document::DiagnosticMessage::Warning,
_doc->fileName(),
line, column,
FindExportedCppTypes::tr(
"must be a string literal to be available in qml editor"));
return false;
}
ContextProperty contextProperty;
contextProperty.name = QString::fromUtf8(nameLit->chars(), nameLit->size());
contextProperty.expression = stringOf(skipQVariant(ast->expression_list->next->value, translationUnit()));
// we want to do lookup later, so also store the line and column of the target scope
translationUnit()->getTokenStartPosition(ast->firstToken(),
&contextProperty.line,
&contextProperty.column);
_contextProperties += contextProperty;
return true;
} }
private: private:
@@ -265,8 +402,8 @@ private:
ExpressionAST *skipStringCall(ExpressionAST *exp) ExpressionAST *skipStringCall(ExpressionAST *exp)
{ {
if (!exp) if (!exp || !exp->asCall())
return 0; return exp;
IdExpressionAST *callName = _builder.IdExpression(); IdExpressionAST *callName = _builder.IdExpression();
CallAST *call = _builder.Call(callName); CallAST *call = _builder.Call(callName);
@@ -381,15 +518,26 @@ static Class *lookupClass(const QString &expression, Scope *scope, TypeOfExpress
return 0; return 0;
} }
static void populate(LanguageUtils::FakeMetaObject::Ptr fmo, Class *klass, static LanguageUtils::FakeMetaObject::Ptr buildFakeMetaObject(
QHash<Class *, LanguageUtils::FakeMetaObject::Ptr> *classes, Class *klass,
TypeOfExpression &typeOf) QHash<Class *, LanguageUtils::FakeMetaObject::Ptr> *fakeMetaObjects,
TypeOfExpression &typeOf)
{ {
using namespace LanguageUtils; using namespace LanguageUtils;
if (FakeMetaObject::Ptr fmo = fakeMetaObjects->value(klass))
return fmo;
FakeMetaObject::Ptr fmo(new FakeMetaObject);
if (!klass)
return fmo;
fakeMetaObjects->insert(klass, fmo);
Overview namePrinter; Overview namePrinter;
classes->insert(klass, fmo); fmo->setClassName(namePrinter(klass->name()));
// add the no-package export, so the cpp name can be used in properties
fmo->addExport(fmo->className(), QmlJS::CppQmlTypes::cppPackage, ComponentVersion());
for (unsigned i = 0; i < klass->memberCount(); ++i) { for (unsigned i = 0; i < klass->memberCount(); ++i) {
Symbol *member = klass->memberAt(i); Symbol *member = klass->memberAt(i);
@@ -454,56 +602,74 @@ static void populate(LanguageUtils::FakeMetaObject::Ptr fmo, Class *klass,
if (klass->baseClassCount() > 0) { if (klass->baseClassCount() > 0) {
BaseClass *base = klass->baseClassAt(0); BaseClass *base = klass->baseClassAt(0);
if (!base->name()) if (!base->name())
return; return fmo;
const QString baseClassName = namePrinter(base->name()); const QString baseClassName = namePrinter(base->name());
fmo->setSuperclassName(baseClassName); fmo->setSuperclassName(baseClassName);
Class *baseClass = lookupClass(baseClassName, klass, typeOf); Class *baseClass = lookupClass(baseClassName, klass, typeOf);
if (!baseClass) if (!baseClass)
return; return fmo;
FakeMetaObject::Ptr baseFmo = classes->value(baseClass); buildFakeMetaObject(baseClass, fakeMetaObjects, typeOf);
if (!baseFmo) {
baseFmo = FakeMetaObject::Ptr(new FakeMetaObject);
populate(baseFmo, baseClass, classes, typeOf);
}
} }
return fmo;
} }
QList<LanguageUtils::FakeMetaObject::ConstPtr> exportedQmlObjects( static void buildExportedQmlObjects(
const Document::Ptr &doc, TypeOfExpression &typeOf,
const Snapshot &snapshot, const QList<ExportedQmlType> &cppExports,
const QList<ExportedQmlType> &exportedTypes) QHash<Class *, LanguageUtils::FakeMetaObject::Ptr> *fakeMetaObjects)
{ {
using namespace LanguageUtils; using namespace LanguageUtils;
QList<FakeMetaObject::ConstPtr> exportedObjects;
QHash<Class *, FakeMetaObject::Ptr> classes;
if (exportedTypes.isEmpty()) if (cppExports.isEmpty())
return exportedObjects; return;
TypeOfExpression typeOf; foreach (const ExportedQmlType &exportedType, cppExports) {
typeOf.init(doc, snapshot); Class *klass = lookupClass(exportedType.typeExpression, exportedType.scope, typeOf);
foreach (const ExportedQmlType &exportedType, exportedTypes) { // accepts a null klass
FakeMetaObject::Ptr fmo(new FakeMetaObject); FakeMetaObject::Ptr fmo = buildFakeMetaObject(klass, fakeMetaObjects, typeOf);
fmo->addExport(exportedType.typeName, fmo->addExport(exportedType.typeName,
exportedType.packageName, exportedType.packageName,
exportedType.version); exportedType.version);
exportedObjects += fmo;
Class *klass = lookupClass(exportedType.typeExpression, exportedType.scope, typeOf);
if (!klass)
continue;
// add the no-package export, so the cpp name can be used in properties
Overview overview;
fmo->addExport(overview(klass->name()), QmlJS::CppQmlTypes::cppPackage, ComponentVersion());
populate(fmo, klass, &classes, typeOf);
} }
}
return exportedObjects; static void buildContextProperties(
const Document::Ptr &doc,
TypeOfExpression &typeOf,
const QList<ContextProperty> &contextPropertyDescriptions,
QHash<Class *, LanguageUtils::FakeMetaObject::Ptr> *fakeMetaObjects,
QMap<QString, QString> *contextProperties)
{
using namespace LanguageUtils;
foreach (const ContextProperty &property, contextPropertyDescriptions) {
Scope *scope = doc->scopeAt(property.line, property.column);
QList<LookupItem> results = typeOf(property.expression, scope);
QString typeName;
if (!results.isEmpty()) {
LookupItem result = results.first();
FullySpecifiedType simpleType = stripPointerAndReference(result.type());
if (NamedType *namedType = simpleType.type()->asNamedType()) {
Scope *typeScope = result.scope();
if (!typeScope)
typeScope = scope; // incorrect but may be an ok fallback
ClassOrNamespace *binding = typeOf.context().lookupType(namedType->name(), typeScope);
if (binding && !binding->symbols().isEmpty()) {
Class *klass = binding->symbols().first()->asClass();
if (klass) {
FakeMetaObject::Ptr fmo = buildFakeMetaObject(klass, fakeMetaObjects, typeOf);
typeName = fmo->className();
}
}
}
}
contextProperties->insert(property.name, typeName);
}
} }
} // anonymous namespace } // anonymous namespace
@@ -513,26 +679,65 @@ FindExportedCppTypes::FindExportedCppTypes(const CPlusPlus::Snapshot &snapshot)
{ {
} }
QList<LanguageUtils::FakeMetaObject::ConstPtr> FindExportedCppTypes::operator()(const CPlusPlus::Document::Ptr &document) void FindExportedCppTypes::operator()(const CPlusPlus::Document::Ptr &document)
{ {
QList<LanguageUtils::FakeMetaObject::ConstPtr> noResults; m_contextProperties.clear();
m_exportedTypes.clear();
// this check only guards against some input errors, if document's source and AST has not // this check only guards against some input errors, if document's source and AST has not
// been guarded properly the source and AST may still become empty/null while this function is running // been guarded properly the source and AST may still become empty/null while this function is running
if (document->source().isEmpty() if (document->source().isEmpty()
|| !document->translationUnit()->ast()) || !document->translationUnit()->ast())
return noResults; return;
FindExportsVisitor finder(document); FindExportsVisitor finder(document);
QList<ExportedQmlType> exports = finder(); finder();
if (CppModelManagerInterface *cppModelManager = CppModelManagerInterface::instance()) { if (CppModelManagerInterface *cppModelManager = CppModelManagerInterface::instance()) {
cppModelManager->setExtraDiagnostics( cppModelManager->setExtraDiagnostics(
document->fileName(), CppModelManagerInterface::ExportedQmlTypesDiagnostic, document->fileName(), CppModelManagerInterface::ExportedQmlTypesDiagnostic,
finder.messages()); finder.messages());
} }
if (exports.isEmpty())
return noResults;
return exportedQmlObjects(document, m_snapshot, exports); // if nothing was found, done
const QList<ContextProperty> contextPropertyDescriptions = finder.contextProperties();
const QList<ExportedQmlType> exports = finder.exportedTypes();
if (exports.isEmpty() && contextPropertyDescriptions.isEmpty())
return;
// context properties need lookup inside function scope, and thus require a full check
Document::Ptr localDoc = document;
if (document->checkMode() != Document::FullCheck && !contextPropertyDescriptions.isEmpty()) {
localDoc = m_snapshot.documentFromSource(document->source(), document->fileName());
localDoc->check();
}
// create a single type of expression (and bindings) for the document
TypeOfExpression typeOf;
typeOf.init(localDoc, m_snapshot);
QHash<Class *, LanguageUtils::FakeMetaObject::Ptr> fakeMetaObjects;
// generate the exports from qmlRegisterType
buildExportedQmlObjects(typeOf, exports, &fakeMetaObjects);
// add the types from the context properties and create a name->cppname map
// also expose types where necessary
buildContextProperties(localDoc, typeOf, contextPropertyDescriptions,
&fakeMetaObjects, &m_contextProperties);
// convert to list of FakeMetaObject::ConstPtr
m_exportedTypes.reserve(fakeMetaObjects.size());
foreach (const LanguageUtils::FakeMetaObject::Ptr &fmo, fakeMetaObjects)
m_exportedTypes += fmo;
}
QList<LanguageUtils::FakeMetaObject::ConstPtr> FindExportedCppTypes::exportedTypes() const
{
return m_exportedTypes;
}
QMap<QString, QString> FindExportedCppTypes::contextProperties() const
{
return m_contextProperties;
} }
bool FindExportedCppTypes::maybeExportsTypes(const Document::Ptr &document) bool FindExportedCppTypes::maybeExportsTypes(const Document::Ptr &document)
@@ -540,9 +745,14 @@ bool FindExportedCppTypes::maybeExportsTypes(const Document::Ptr &document)
if (!document->control()) if (!document->control())
return false; return false;
const QByteArray qmlRegisterTypeToken("qmlRegisterType"); const QByteArray qmlRegisterTypeToken("qmlRegisterType");
const QByteArray setContextPropertyToken("setContextProperty");
if (document->control()->findIdentifier( if (document->control()->findIdentifier(
qmlRegisterTypeToken.constData(), qmlRegisterTypeToken.size())) { qmlRegisterTypeToken.constData(), qmlRegisterTypeToken.size())) {
return true; return true;
} }
if (document->control()->findIdentifier(
setContextPropertyToken.constData(), setContextPropertyToken.size())) {
return true;
}
return false; return false;
} }

View File

@@ -37,6 +37,7 @@
#include <languageutils/fakemetaobject.h> #include <languageutils/fakemetaobject.h>
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtCore/QMap>
namespace QmlJSTools { namespace QmlJSTools {
@@ -47,12 +48,17 @@ public:
FindExportedCppTypes(const CPlusPlus::Snapshot &snapshot); FindExportedCppTypes(const CPlusPlus::Snapshot &snapshot);
// document must have a valid source and ast for the duration of the call // document must have a valid source and ast for the duration of the call
QList<LanguageUtils::FakeMetaObject::ConstPtr> operator()(const CPlusPlus::Document::Ptr &document); void operator()(const CPlusPlus::Document::Ptr &document);
QList<LanguageUtils::FakeMetaObject::ConstPtr> exportedTypes() const;
QMap<QString, QString> contextProperties() const;
static bool maybeExportsTypes(const CPlusPlus::Document::Ptr &document); static bool maybeExportsTypes(const CPlusPlus::Document::Ptr &document);
private: private:
CPlusPlus::Snapshot m_snapshot; CPlusPlus::Snapshot m_snapshot;
QList<LanguageUtils::FakeMetaObject::ConstPtr> m_exportedTypes;
QMap<QString, QString> m_contextProperties;
}; };
} // namespace QmlJSTools } // namespace QmlJSTools

View File

@@ -717,7 +717,8 @@ void ModelManager::updateCppQmlTypes(ModelManager *qmlModelManager,
CPlusPlus::CppModelManagerInterface *cppModelManager, CPlusPlus::CppModelManagerInterface *cppModelManager,
QMap<QString, QPair<CPlusPlus::Document::Ptr, bool> > documents) QMap<QString, QPair<CPlusPlus::Document::Ptr, bool> > documents)
{ {
CppQmlTypeHash newCppTypes = qmlModelManager->cppQmlTypes(); CppDataHash newData = qmlModelManager->cppData();
CPlusPlus::Snapshot snapshot = cppModelManager->snapshot(); CPlusPlus::Snapshot snapshot = cppModelManager->snapshot();
FindExportedCppTypes finder(snapshot); FindExportedCppTypes finder(snapshot);
@@ -727,28 +728,33 @@ void ModelManager::updateCppQmlTypes(ModelManager *qmlModelManager,
const bool scan = pair.second; const bool scan = pair.second;
const QString fileName = doc->fileName(); const QString fileName = doc->fileName();
if (!scan) { if (!scan) {
newCppTypes.remove(fileName); newData.remove(fileName);
continue; continue;
} }
QList<LanguageUtils::FakeMetaObject::ConstPtr> exported = finder(doc); finder(doc);
if (!exported.isEmpty()) QList<LanguageUtils::FakeMetaObject::ConstPtr> exported = finder.exportedTypes();
newCppTypes[fileName] = exported; QMap<QString, QString> contextProperties = finder.contextProperties();
else if (exported.isEmpty() && contextProperties.isEmpty()) {
newCppTypes.remove(fileName); newData.remove(fileName);
} else {
CppData &data = newData[fileName];
data.exportedTypes = exported;
data.contextProperties = contextProperties;
}
doc->releaseSourceAndAST(); doc->releaseSourceAndAST();
} }
QMutexLocker locker(&qmlModelManager->m_cppTypesMutex); QMutexLocker locker(&qmlModelManager->m_cppDataMutex);
qmlModelManager->m_cppTypes = newCppTypes; qmlModelManager->m_cppDataHash = newData;
} }
ModelManagerInterface::CppQmlTypeHash ModelManager::cppQmlTypes() const ModelManager::CppDataHash ModelManager::cppData() const
{ {
QMutexLocker locker(&m_cppTypesMutex); QMutexLocker locker(&m_cppDataMutex);
return m_cppTypes; return m_cppDataHash;
} }
LibraryInfo ModelManager::builtins(const Document::Ptr &doc) const LibraryInfo ModelManager::builtins(const Document::Ptr &doc) const

View File

@@ -91,7 +91,7 @@ public:
virtual void loadPluginTypes(const QString &libraryPath, const QString &importPath, virtual void loadPluginTypes(const QString &libraryPath, const QString &importPath,
const QString &importUri, const QString &importVersion); const QString &importUri, const QString &importVersion);
virtual CppQmlTypeHash cppQmlTypes() const; virtual CppDataHash cppData() const;
virtual QmlJS::LibraryInfo builtins(const QmlJS::Document::Ptr &doc) const; virtual QmlJS::LibraryInfo builtins(const QmlJS::Document::Ptr &doc) const;
@@ -140,8 +140,9 @@ private:
QTimer *m_updateCppQmlTypesTimer; QTimer *m_updateCppQmlTypesTimer;
QMap<QString, QPair<CPlusPlus::Document::Ptr, bool> > m_queuedCppDocuments; QMap<QString, QPair<CPlusPlus::Document::Ptr, bool> > m_queuedCppDocuments;
CppQmlTypeHash m_cppTypes;
mutable QMutex m_cppTypesMutex; CppDataHash m_cppDataHash;
mutable QMutex m_cppDataMutex;
// project integration // project integration
QMap<ProjectExplorer::Project *, ProjectInfo> m_projects; QMap<ProjectExplorer::Project *, ProjectInfo> m_projects;