From 7fb87fbb0609af9a52b1a2d6a0f7f9290fec87ae Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Wed, 13 Nov 2013 16:31:04 +0100 Subject: qmljs: fingerprints for documents, libraries and FakeMetaObjects Change-Id: Ib9c9b86fbed19539dc42696292bdb3b93dd1b575 Reviewed-by: Thomas Hartmann --- src/libs/qmljs/qmljsdocument.cpp | 118 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 2 deletions(-) (limited to 'src/libs/qmljs/qmljsdocument.cpp') diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp index 7d8db768be..bdc1e8c5b4 100644 --- a/src/libs/qmljs/qmljsdocument.cpp +++ b/src/libs/qmljs/qmljsdocument.cpp @@ -34,8 +34,13 @@ #include #include +#include + +#include #include +#include + using namespace QmlJS; using namespace QmlJS::AST; @@ -205,6 +210,16 @@ void Document::setLanguage(Language::Enum l) _language = l; } +QString Document::importId() const +{ + return path(); +} + +QByteArray Document::fingerprint() const +{ + return _fingerprint; +} + AST::UiProgram *Document::qmlProgram() const { return cast(_ast); @@ -246,6 +261,9 @@ QString Document::source() const void Document::setSource(const QString &source) { _source = source; + QCryptographicHash sha(QCryptographicHash::Sha1); + sha.addData(source.toUtf8()); + _fingerprint = sha.result(); } int Document::editorRevision() const @@ -374,21 +392,88 @@ LibraryInfo::LibraryInfo(Status status) : _status(status) , _dumpStatus(NoTypeInfo) { + updateFingerprint(); } -LibraryInfo::LibraryInfo(const QmlDirParser &parser) +LibraryInfo::LibraryInfo(const QmlDirParser &parser, const QByteArray &fingerprint) : _status(Found) , _components(parser.components().values()) , _plugins(parser.plugins()) , _typeinfos(parser.typeInfos()) + , _fingerprint(fingerprint) , _dumpStatus(NoTypeInfo) { + if (_fingerprint.isEmpty()) + updateFingerprint(); } LibraryInfo::~LibraryInfo() { } +QByteArray LibraryInfo::calculateFingerprint() const +{ + QCryptographicHash hash(QCryptographicHash::Sha1); + hash.addData(reinterpret_cast(&_status), sizeof(_status)); + int len = _components.size(); + hash.addData(reinterpret_cast(&len), sizeof(len)); + foreach (const QmlDirParser::Component &component, _components) { + len = component.fileName.size(); + hash.addData(reinterpret_cast(&len), sizeof(len)); + hash.addData(reinterpret_cast(component.fileName.constData()), len * sizeof(QChar)); + hash.addData(reinterpret_cast(&component.majorVersion), sizeof(component.majorVersion)); + hash.addData(reinterpret_cast(&component.minorVersion), sizeof(component.minorVersion)); + len = component.typeName.size(); + hash.addData(reinterpret_cast(&len), sizeof(len)); + hash.addData(reinterpret_cast(component.typeName.constData()), component.typeName.size() * sizeof(QChar)); + int flags = (component.singleton ? (1 << 0) : 0) + (component.internal ? (1 << 1) : 0); + hash.addData(reinterpret_cast(&flags), sizeof(flags)); + } + len = _plugins.size(); + hash.addData(reinterpret_cast(&len), sizeof(len)); + foreach (const QmlDirParser::Plugin &plugin, _plugins) { + len = plugin.path.size(); + hash.addData(reinterpret_cast(&len), sizeof(len)); + hash.addData(reinterpret_cast(plugin.path.constData()), len * sizeof(QChar)); + len = plugin.name.size(); + hash.addData(reinterpret_cast(&len), sizeof(len)); + hash.addData(reinterpret_cast(plugin.name.constData()), len * sizeof(QChar)); + } + len = _typeinfos.size(); + hash.addData(reinterpret_cast(&len), sizeof(len)); + foreach (const QmlDirParser::TypeInfo &typeinfo, _typeinfos) { + len = typeinfo.fileName.size(); + hash.addData(reinterpret_cast(&len), sizeof(len)); + hash.addData(reinterpret_cast(typeinfo.fileName.constData()), len * sizeof(QChar)); + } + len = _metaObjects.size(); + hash.addData(reinterpret_cast(&len), sizeof(len)); + QList metaFingerprints; + foreach (const LanguageUtils::FakeMetaObject::ConstPtr &metaObject, _metaObjects) + metaFingerprints.append(metaObject->fingerprint()); + std::sort(metaFingerprints.begin(), metaFingerprints.end()); + foreach (const QByteArray &fp, metaFingerprints) + hash.addData(fp); + hash.addData(reinterpret_cast(&_dumpStatus), sizeof(_dumpStatus)); + len = _dumpError.size(); // localization dependent (avoid?) + hash.addData(reinterpret_cast(&len), sizeof(len)); + hash.addData(reinterpret_cast(_dumpError.constData()), len * sizeof(QChar)); + + len = _moduleApis.size(); + hash.addData(reinterpret_cast(&len), sizeof(len)); + foreach (const ModuleApiInfo &moduleInfo, _moduleApis) + moduleInfo.addToHash(hash); // make it order independent? + + QByteArray res(hash.result()); + res.append('L'); + return res; +} + +void LibraryInfo::updateFingerprint() +{ + _fingerprint = calculateFingerprint(); +} + Snapshot::Snapshot() { } @@ -410,16 +495,33 @@ void Snapshot::insert(const Document::Ptr &document, bool allowInvalid) if (document && (allowInvalid || document->qmlProgram() || document->jsProgram())) { const QString fileName = document->fileName(); const QString path = document->path(); - remove(fileName); _documentsByPath[path].append(document); _documents.insert(fileName, document); + CoreImport cImport; + cImport.importId = document->importId(); + cImport.language = document->language(); + cImport.possibleExports << Export(ImportKey(ImportType::File, document->path()), + QString(), true); + cImport.fingerprint = document->fingerprint(); + _dependencies.addCoreImport(cImport); } } void Snapshot::insertLibraryInfo(const QString &path, const LibraryInfo &info) { + QTC_CHECK(info.fingerprint() == info.calculateFingerprint()); _libraries.insert(QDir::cleanPath(path), info); + CoreImport cImport; + cImport.importId = path; + cImport.language = Language::Unknown; + foreach (const ModuleApiInfo &moduleInfo, info.moduleApis()) { + ImportKey iKey(ImportType::Library, moduleInfo.uri, moduleInfo.version.majorVersion(), + moduleInfo.version.minorVersion()); + cImport.possibleExports << Export(iKey, path, true); + } + cImport.fingerprint = info.fingerprint(); + _dependencies.addCoreImport(cImport); } void Snapshot::remove(const QString &fileName) @@ -473,3 +575,15 @@ LibraryInfo Snapshot::libraryInfo(const QString &path) const { return _libraries.value(QDir::cleanPath(path)); } + + +void ModuleApiInfo::addToHash(QCryptographicHash &hash) const +{ + int len = uri.length(); + hash.addData(reinterpret_cast(&len), sizeof(len)); + hash.addData(reinterpret_cast(uri.constData()), len * sizeof(QChar)); + version.addToHash(hash); + len = cppName.length(); + hash.addData(reinterpret_cast(&len), sizeof(len)); + hash.addData(reinterpret_cast(cppName.constData()), len * sizeof(QChar)); +} -- cgit v1.2.1