qmljs: fingerprints for documents, libraries and FakeMetaObjects

Change-Id: Ib9c9b86fbed19539dc42696292bdb3b93dd1b575
Reviewed-by: Thomas Hartmann <Thomas.Hartmann@digia.com>
This commit is contained in:
Fawzi Mohamed
2013-11-13 16:31:04 +01:00
parent e1b44e870f
commit 7fb87fbb06
11 changed files with 360 additions and 24 deletions

View File

@@ -34,8 +34,13 @@
#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;
@@ -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<UiProgram *>(_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<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()
{
}
@@ -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<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));
}