diff options
Diffstat (limited to 'src/libs/qmljs/qmljsdocument.cpp')
-rw-r--r-- | src/libs/qmljs/qmljsdocument.cpp | 158 |
1 files changed, 156 insertions, 2 deletions
diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp index fe169f795c..68fb5eadd5 100644 --- a/src/libs/qmljs/qmljsdocument.cpp +++ b/src/libs/qmljs/qmljsdocument.cpp @@ -30,11 +30,17 @@ #include "qmljsdocument.h" #include "qmljsbind.h" #include "qmljsconstants.h" +#include "qmljsimportdependencies.h" #include <qmljs/parser/qmljslexer_p.h> #include <qmljs/parser/qmljsparser_p.h> +#include <utils/qtcassert.h> + +#include <QCryptographicHash> #include <QDir> +#include <algorithm> + using namespace QmlJS; using namespace QmlJS::AST; @@ -204,6 +210,16 @@ void Document::setLanguage(Language::Enum l) _language = l; } +QString Document::importId() const +{ + return _fileName; +} + +QByteArray Document::fingerprint() const +{ + return _fingerprint; +} + AST::UiProgram *Document::qmlProgram() const { return cast<UiProgram *>(_ast); @@ -245,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 @@ -373,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<const char *>(&_status), sizeof(_status)); + int len = _components.size(); + hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); + foreach (const QmlDirParser::Component &component, _components) { + len = component.fileName.size(); + hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); + hash.addData(reinterpret_cast<const char *>(component.fileName.constData()), len * sizeof(QChar)); + hash.addData(reinterpret_cast<const char *>(&component.majorVersion), sizeof(component.majorVersion)); + hash.addData(reinterpret_cast<const char *>(&component.minorVersion), sizeof(component.minorVersion)); + len = component.typeName.size(); + hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); + hash.addData(reinterpret_cast<const char *>(component.typeName.constData()), component.typeName.size() * sizeof(QChar)); + int flags = (component.singleton ? (1 << 0) : 0) + (component.internal ? (1 << 1) : 0); + hash.addData(reinterpret_cast<const char *>(&flags), sizeof(flags)); + } + len = _plugins.size(); + hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); + foreach (const QmlDirParser::Plugin &plugin, _plugins) { + len = plugin.path.size(); + hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); + hash.addData(reinterpret_cast<const char *>(plugin.path.constData()), len * sizeof(QChar)); + len = plugin.name.size(); + hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); + hash.addData(reinterpret_cast<const char *>(plugin.name.constData()), len * sizeof(QChar)); + } + len = _typeinfos.size(); + hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); + foreach (const QmlDirParser::TypeInfo &typeinfo, _typeinfos) { + len = typeinfo.fileName.size(); + hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); + hash.addData(reinterpret_cast<const char *>(typeinfo.fileName.constData()), len * sizeof(QChar)); + } + len = _metaObjects.size(); + hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); + QList<QByteArray> 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<const char *>(&_dumpStatus), sizeof(_dumpStatus)); + len = _dumpError.size(); // localization dependent (avoid?) + hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); + hash.addData(reinterpret_cast<const char *>(_dumpError.constData()), len * sizeof(QChar)); + + len = _moduleApis.size(); + hash.addData(reinterpret_cast<const char *>(&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() { } @@ -396,21 +482,67 @@ Snapshot::~Snapshot() { } +Snapshot::Snapshot(const Snapshot &o) + : _documents(o._documents), + _documentsByPath(o._documentsByPath), + _libraries(o._libraries), + _dependencies(o._dependencies) +{ +} + 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, fileName), + 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); + if (!info.wasFound()) return; + CoreImport cImport; + cImport.importId = path; + cImport.language = Language::Unknown; + QSet<ImportKey> packages; + foreach (const ModuleApiInfo &moduleInfo, info.moduleApis()) { + ImportKey iKey(ImportType::Library, moduleInfo.uri, moduleInfo.version.majorVersion(), + moduleInfo.version.minorVersion()); + packages.insert(iKey); + } + foreach (const LanguageUtils::FakeMetaObject::ConstPtr &metaO, info.metaObjects()) { + foreach (const LanguageUtils::FakeMetaObject::Export &e, metaO->exports()) { + ImportKey iKey(ImportType::Library, e.package, e.version.majorVersion(), + e.version.minorVersion()); + packages.insert(iKey); + } + } + + QStringList splitPath = path.split(QLatin1Char('/')); + foreach (const ImportKey &importKey, packages) { + QString requiredPath = QStringList(splitPath.mid(0, splitPath.size() - importKey.splitPath.size())) + .join(QLatin1String("/")); + cImport.possibleExports << Export(importKey, requiredPath, true); + } + foreach (const QmlDirParser::Component &component, info.components()) { + foreach (const Export &e, cImport.possibleExports) + // renaming of type name not really represented here... fix? + _dependencies.addExport(component.fileName, e.exportName, e.pathRequired); + } + cImport.fingerprint = info.fingerprint(); + _dependencies.addCoreImport(cImport); } void Snapshot::remove(const QString &fileName) @@ -427,6 +559,16 @@ void Snapshot::remove(const QString &fileName) } } +const QmlJS::ImportDependencies *Snapshot::importDependencies() const +{ + return &_dependencies; +} + +QmlJS::ImportDependencies *Snapshot::importDependencies() +{ + return &_dependencies; +} + Document::MutablePtr Snapshot::documentFromSource( const QString &code, const QString &fileName, Language::Enum language) const @@ -454,3 +596,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<const char *>(&len), sizeof(len)); + hash.addData(reinterpret_cast<const char *>(uri.constData()), len * sizeof(QChar)); + version.addToHash(hash); + len = cppName.length(); + hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); + hash.addData(reinterpret_cast<const char *>(cppName.constData()), len * sizeof(QChar)); +} |