diff options
author | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-08-14 18:30:29 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2018-03-14 15:34:01 +0000 |
commit | 60245e55d7551f525c951d8d866aab081be88a69 (patch) | |
tree | a835326ccc87ea93d7c749f9f0f42f27d8ab1db2 /src | |
parent | 274726efb0bbc5055f02b1b76f2481564ad27f46 (diff) |
qmake: Change source identifier type in ProString
The strings remember in which file they were created/assigned.
However, this used a non-counting reference to a ProFile, which could
become dangling. If a subsequent ProFile re-used the exact same address,
a string's source would be mis-identified, which would be fatal in
conjunction with discard_from().
Since we actually need only a unique id for comparison, let's use an
integer for that.
comment on cherry-pick: this is actually a lot more than a cherry-pick,
because the file ids need to be aware of the dual VFS which was
concurrently introduced on the qtc side.
Started-by: Simon Hausmann <simon.hausmann@qt.io>
Change-Id: I395153afaf7c835d0119690ee7f4b915e6f90d4a
(cherry picked from qtbase/190aa94be7f5e146bef44862b974d733755cec85)
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp | 9 | ||||
-rw-r--r-- | src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp | 24 | ||||
-rw-r--r-- | src/plugins/qmakeprojectmanager/qmakeparsernodes.h | 4 | ||||
-rw-r--r-- | src/plugins/qmakeprojectmanager/qmakeproject.cpp | 11 | ||||
-rw-r--r-- | src/plugins/qtsupport/profilereader.cpp | 9 | ||||
-rw-r--r-- | src/plugins/qtsupport/profilereader.h | 4 | ||||
-rw-r--r-- | src/shared/proparser/profileevaluator.h | 2 | ||||
-rw-r--r-- | src/shared/proparser/proitems.cpp | 5 | ||||
-rw-r--r-- | src/shared/proparser/proitems.h | 10 | ||||
-rw-r--r-- | src/shared/proparser/prowriter.cpp | 2 | ||||
-rw-r--r-- | src/shared/proparser/qmakebuiltins.cpp | 23 | ||||
-rw-r--r-- | src/shared/proparser/qmakeevaluator.cpp | 18 | ||||
-rw-r--r-- | src/shared/proparser/qmakeevaluator.h | 3 | ||||
-rw-r--r-- | src/shared/proparser/qmakeparser.cpp | 86 | ||||
-rw-r--r-- | src/shared/proparser/qmakeparser.h | 14 | ||||
-rw-r--r-- | src/shared/proparser/qmakevfs.cpp | 149 | ||||
-rw-r--r-- | src/shared/proparser/qmakevfs.h | 55 |
17 files changed, 243 insertions, 185 deletions
diff --git a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp index 6e071c90e0..df327d7654 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp @@ -160,10 +160,13 @@ static void createTree(const QmakePriFile *pri, QmakePriFileNode *node, const Fi QString errorMessage; // Prefer the cumulative file if it's non-empty, based on the assumption // that it contains more "stuff". - vfs->readFile(file.toString(), QMakeVfs::VfsCumulative, &contents, &errorMessage); + int cid = vfs->idForFileName(file.toString(), QMakeVfs::VfsCumulative); + vfs->readFile(cid, &contents, &errorMessage); // If the cumulative evaluation botched the file too much, try the exact one. - if (contents.isEmpty()) - vfs->readFile(file.toString(), QMakeVfs::VfsExact, &contents, &errorMessage); + if (contents.isEmpty()) { + int eid = vfs->idForFileName(file.toString(), QMakeVfs::VfsExact); + vfs->readFile(eid, &contents, &errorMessage); + } auto resourceNode = new ResourceEditor::ResourceTopLevelNode(file, false, contents, vfolder); vfolder->addNode(resourceNode); } diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index 4c47e34d2f..9e0b1d248c 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -237,7 +237,8 @@ QmakePriFile::~QmakePriFile() void QmakePriFile::scheduleUpdate() { - QtSupport::ProFileCacheManager::instance()->discardFile(filePath().toString()); + QtSupport::ProFileCacheManager::instance()->discardFile( + filePath().toString(), m_project->qmakeVfs()); m_qmakeProFile->scheduleUpdate(QmakeProFile::ParseLater); } @@ -292,11 +293,11 @@ static QStringList fileListForVar( } void QmakePriFile::extractSources( - QHash<const ProFile *, QmakePriFileEvalResult *> proToResult, QmakePriFileEvalResult *fallback, + QHash<int, QmakePriFileEvalResult *> proToResult, QmakePriFileEvalResult *fallback, QVector<ProFileEvaluator::SourceFile> sourceFiles, FileType type) { foreach (const ProFileEvaluator::SourceFile &source, sourceFiles) { - QmakePriFileEvalResult *result = proToResult.value(source.proFile); + auto *result = proToResult.value(source.proFileId); if (!result) result = fallback; result->foundFiles[type].insert(FileName::fromString(source.fileName)); @@ -304,12 +305,12 @@ void QmakePriFile::extractSources( } void QmakePriFile::extractInstalls( - QHash<const ProFile *, QmakePriFileEvalResult *> proToResult, QmakePriFileEvalResult *fallback, + QHash<int, QmakePriFileEvalResult *> proToResult, QmakePriFileEvalResult *fallback, const InstallsList &installList) { for (const InstallsItem &item : installList.items) { for (const ProFileEvaluator::SourceFile &source : item.files) { - auto *result = proToResult.value(source.proFile); + auto *result = proToResult.value(source.proFileId); if (!result) result = fallback; result->folders.insert(FileName::fromString(source.fileName)); @@ -621,7 +622,8 @@ bool QmakePriFile::saveModifiedEditors() return false; // force instant reload of ourselves - QtSupport::ProFileCacheManager::instance()->discardFile(filePath().toString()); + QtSupport::ProFileCacheManager::instance()->discardFile( + filePath().toString(), m_project->qmakeVfs()); QmakeProject::notifyChanged(filePath()); return true; } @@ -701,7 +703,7 @@ QPair<ProFile *, QStringList> QmakePriFile::readProFile(const QString &file) QMakeVfs vfs; QtSupport::ProMessageHandler handler; QMakeParser parser(nullptr, &vfs, &handler); - includeFile = parser.parsedProBlock(QStringRef(&contents), file, 1); + includeFile = parser.parsedProBlock(QStringRef(&contents), 0, file, 1); } return qMakePair(includeFile, lines); } @@ -738,7 +740,7 @@ bool QmakePriFile::renameFile(const QString &oldName, QMakeParser parser(nullptr, nullptr, nullptr); QString contents = lines.join(QLatin1Char('\n')); includeFile = parser.parsedProBlock(QStringRef(&contents), - filePath().toString(), 1, QMakeParser::FullGrammar); + 0, filePath().toString(), 1, QMakeParser::FullGrammar); QTC_ASSERT(includeFile, return false); // The file should still be valid after what we did. ProWriter::addFiles(includeFile, &lines, @@ -1294,7 +1296,7 @@ QmakeEvalResult *QmakeProFile::evaluate(const QmakeEvalInput &input) result->includedFiles.proFile = pro; result->includedFiles.name = input.projectFilePath; - QHash<const ProFile *, QmakePriFileEvalResult *> proToResult; + QHash<int, QmakePriFileEvalResult *> proToResult; result->projectType = proFileTemplateTypeToProjectType( @@ -1332,7 +1334,7 @@ QmakeEvalResult *QmakeProFile::evaluate(const QmakeEvalInput &input) childTree->proFile = child; childTree->name = childName; current->children.insert(childName, childTree); - proToResult[child] = &childTree->result; + proToResult[child->id()] = &childTree->result; } } toBuild.append(current->children.values()); @@ -1368,7 +1370,7 @@ QmakeEvalResult *QmakeProFile::evaluate(const QmakeEvalInput &input) childTree->proFile = child; childTree->name = childName; current->children.insert(childName, childTree); - proToResult[child] = &childTree->result; + proToResult[child->id()] = &childTree->result; } } toBuild.append(current->children.values()); diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h index 27dad4aae9..0889d23022 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h @@ -201,11 +201,11 @@ private: static QStringList baseVPaths(QtSupport::ProFileReader *reader, const QString &projectDir, const QString &buildDir); static QStringList fullVPaths(const QStringList &baseVPaths, QtSupport::ProFileReader *reader, const QString &qmakeVariable, const QString &projectDir); static void extractSources( - QHash<const ProFile *, Internal::QmakePriFileEvalResult *> proToResult, + QHash<int, Internal::QmakePriFileEvalResult *> proToResult, Internal::QmakePriFileEvalResult *fallback, QVector<ProFileEvaluator::SourceFile> sourceFiles, ProjectExplorer::FileType type); static void extractInstalls( - QHash<const ProFile *, Internal::QmakePriFileEvalResult *> proToResult, + QHash<int, Internal::QmakePriFileEvalResult *> proToResult, Internal::QmakePriFileEvalResult *fallback, const InstallsList &installList); static void processValues(Internal::QmakePriFileEvalResult &result); diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 7d10a31cd8..44ebc927b6 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -372,12 +372,14 @@ void QmakeProject::updateQmlJSCodeModel() QString errorMessage; foreach (const QString &rc, exactResources) { QString contents; - if (m_qmakeVfs->readFile(rc, QMakeVfs::VfsExact, &contents, &errorMessage) == QMakeVfs::ReadOk) + int id = m_qmakeVfs->idForFileName(rc, QMakeVfs::VfsExact); + if (m_qmakeVfs->readFile(id, &contents, &errorMessage) == QMakeVfs::ReadOk) projectInfo.resourceFileContents[rc] = contents; } foreach (const QString &rc, cumulativeResources) { QString contents; - if (m_qmakeVfs->readFile(rc, QMakeVfs::VfsCumulative, &contents, &errorMessage) == QMakeVfs::ReadOk) + int id = m_qmakeVfs->idForFileName(rc, QMakeVfs::VfsCumulative); + if (m_qmakeVfs->readFile(id, &contents, &errorMessage) == QMakeVfs::ReadOk) projectInfo.resourceFileContents[rc] = contents; } if (!hasQmlLib) { @@ -734,7 +736,7 @@ void QmakeProject::destroyProFileReader(QtSupport::ProFileReader *reader) QString dir = projectFilePath().toString(); if (!dir.endsWith(QLatin1Char('/'))) dir += QLatin1Char('/'); - QtSupport::ProFileCacheManager::instance()->discardFiles(dir); + QtSupport::ProFileCacheManager::instance()->discardFiles(dir, qmakeVfs()); QtSupport::ProFileCacheManager::instance()->decRefCount(); m_qmakeGlobals.reset(); @@ -840,7 +842,8 @@ void QmakeProject::setAllBuildConfigurationsEnabled(bool enabled) static void notifyChangedHelper(const FileName &fileName, QmakeProFile *file) { if (file->filePath() == fileName) { - QtSupport::ProFileCacheManager::instance()->discardFile(fileName.toString()); + QtSupport::ProFileCacheManager::instance()->discardFile( + fileName.toString(), file->project()->qmakeVfs()); file->scheduleUpdate(QmakeProFile::ParseNow); } diff --git a/src/plugins/qtsupport/profilereader.cpp b/src/plugins/qtsupport/profilereader.cpp index 0985a64b75..86ec0f16d7 100644 --- a/src/plugins/qtsupport/profilereader.cpp +++ b/src/plugins/qtsupport/profilereader.cpp @@ -166,16 +166,17 @@ void ProFileCacheManager::clear() // loop is concerned. Use a shared pointer once this is not true anymore. delete m_cache; m_cache = 0; + QMakeVfs::clearIds(); } -void ProFileCacheManager::discardFiles(const QString &prefix) +void ProFileCacheManager::discardFiles(const QString &prefix, QMakeVfs *vfs) { if (m_cache) - m_cache->discardFiles(prefix); + m_cache->discardFiles(prefix, vfs); } -void ProFileCacheManager::discardFile(const QString &fileName) +void ProFileCacheManager::discardFile(const QString &fileName, QMakeVfs *vfs) { if (m_cache) - m_cache->discardFile(fileName); + m_cache->discardFile(fileName, vfs); } diff --git a/src/plugins/qtsupport/profilereader.h b/src/plugins/qtsupport/profilereader.h index 5e53d2d2dc..c2245b488a 100644 --- a/src/plugins/qtsupport/profilereader.h +++ b/src/plugins/qtsupport/profilereader.h @@ -93,8 +93,8 @@ class QTSUPPORT_EXPORT ProFileCacheManager : public QObject public: static ProFileCacheManager *instance() { return s_instance; } ProFileCache *cache(); - void discardFiles(const QString &prefix); - void discardFile(const QString &fileName); + void discardFiles(const QString &prefix, QMakeVfs *vfs); + void discardFile(const QString &fileName, QMakeVfs *vfs); void incRefCount(); void decRefCount(); diff --git a/src/shared/proparser/profileevaluator.h b/src/shared/proparser/profileevaluator.h index b0116aebd4..ce1675dd4b 100644 --- a/src/shared/proparser/profileevaluator.h +++ b/src/shared/proparser/profileevaluator.h @@ -55,7 +55,7 @@ public: struct SourceFile { QString fileName; - const ProFile *proFile; + int proFileId; }; // Call this from a concurrency-free context diff --git a/src/shared/proparser/proitems.cpp b/src/shared/proparser/proitems.cpp index 3c4fe3bc2e..30ddef65c4 100644 --- a/src/shared/proparser/proitems.cpp +++ b/src/shared/proparser/proitems.cpp @@ -474,9 +474,10 @@ bool ProStringList::contains(const char *str, Qt::CaseSensitivity cs) const return false; } -ProFile::ProFile(const QString &fileName) +ProFile::ProFile(int id, const QString &fileName) : m_refCount(1), m_fileName(fileName), + m_id(id), m_ok(true), m_hostBuild(false) { @@ -493,7 +494,7 @@ ProString ProFile::getStr(const ushort *&tPtr) { uint len = *tPtr++; ProString ret(items(), tPtr - tokPtr(), len); - ret.setSource(this); + ret.setSource(m_id); tPtr += len; return ret; } diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h index efcd888c72..6199efc8c7 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -69,8 +69,8 @@ public: void setValue(const QString &str); void clear() { m_string.clear(); m_length = 0; } ProString &setSource(const ProString &other) { m_file = other.m_file; return *this; } - ProString &setSource(const ProFile *pro) { m_file = pro; return *this; } - const ProFile *sourceFile() const { return m_file; } + ProString &setSource(int id) { m_file = id; return *this; } + int sourceFile() const { return m_file; } ProString &prepend(const ProString &other); ProString &append(const ProString &other, bool *pending = 0); @@ -159,7 +159,7 @@ private: QString m_string; int m_offset, m_length; - const ProFile *m_file; + int m_file; mutable uint m_hash; QChar *prepareExtend(int extraLen, int thisTarget, int extraTarget); uint updatedHash() const; @@ -332,9 +332,10 @@ enum ProToken { class QMAKE_EXPORT ProFile { public: - explicit ProFile(const QString &fileName); + ProFile(int id, const QString &fileName); ~ProFile(); + int id() const { return m_id; } QString fileName() const { return m_fileName; } QString directoryName() const { return m_directoryName; } const QString &items() const { return m_proitems; } @@ -359,6 +360,7 @@ private: QString m_proitems; QString m_fileName; QString m_directoryName; + int m_id; bool m_ok; bool m_hostBuild; }; diff --git a/src/shared/proparser/prowriter.cpp b/src/shared/proparser/prowriter.cpp index 046143c8ef..0d717d9ce9 100644 --- a/src/shared/proparser/prowriter.cpp +++ b/src/shared/proparser/prowriter.cpp @@ -176,7 +176,7 @@ QString ProWriter::compileScope(const QString &scope) if (scope.isEmpty()) return QString(); QMakeParser parser(0, 0, 0); - ProFile *includeFile = parser.parsedProBlock(QStringRef(&scope), QLatin1String("no-file"), 1); + ProFile *includeFile = parser.parsedProBlock(QStringRef(&scope), 0, QLatin1String("no-file"), 1); if (!includeFile) return QString(); QString result = includeFile->items(); diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index d93efd53eb..4ca018c5de 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -436,13 +436,16 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode, QMakeVfs::VfsFlags flags, const QString &contents) { + int oldId = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsAccessedOnly); + int id = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsCreate); QString errStr; - if (!m_vfs->writeFile(fn, mode, flags, contents, &errStr)) { + if (!m_vfs->writeFile(id, mode, flags, contents, &errStr)) { evalError(fL1S("Cannot write %1file %2: %3") .arg(ctx, QDir::toNativeSeparators(fn), errStr)); return ReturnFalse; } - m_parser->discardFileFromCache(fn); + if (oldId) + m_parser->discardFileFromCache(oldId); return ReturnTrue; } @@ -709,9 +712,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( after = args[3]; const ProStringList &var = values(map(args.at(0))); if (!var.isEmpty()) { - const ProFile *src = currentProFile(); + int src = currentFileId(); for (const ProString &v : var) - if (const ProFile *s = v.sourceFile()) { + if (int s = v.sourceFile()) { src = s; break; } @@ -1062,7 +1065,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( dirs.append(fname + QLatin1Char('/')); } if (regex.exactMatch(qdir[i])) - ret += ProString(fname).setSource(currentProFile()); + ret += ProString(fname).setSource(currentFileId()); } } } @@ -1329,7 +1332,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( return ReturnFalse; } QString fn = resolvePath(args.at(0).toQString(m_tmp1)); - ProFile *pro = m_parser->parsedProFile(fn, QMakeParser::ParseOnlyCached); + QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact); + int pro = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsAccessedOnly); if (!pro) return ReturnFalse; ProValueMap &vmap = m_valuemapStack.first(); @@ -1349,18 +1353,17 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ++vit; } for (auto fit = m_functionDefs.testFunctions.begin(); fit != m_functionDefs.testFunctions.end(); ) { - if (fit->pro() == pro) + if (fit->pro()->id() == pro) fit = m_functionDefs.testFunctions.erase(fit); else ++fit; } for (auto fit = m_functionDefs.replaceFunctions.begin(); fit != m_functionDefs.replaceFunctions.end(); ) { - if (fit->pro() == pro) + if (fit->pro()->id() == pro) fit = m_functionDefs.replaceFunctions.erase(fit); else ++fit; } - pro->deref(); ProStringList &iif = m_valuemapStack.first()[ProKey("QMAKE_INTERNAL_INCLUDED_FILES")]; int idx = iif.indexOf(ProString(fn)); if (idx >= 0) @@ -1405,7 +1408,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( VisitReturn ret = ReturnFalse; QString contents = args.join(statics.field_sep); ProFile *pro = m_parser->parsedProBlock(QStringRef(&contents), - m_current.pro->fileName(), m_current.line); + 0, m_current.pro->fileName(), m_current.line); if (m_cumulative || pro->isOk()) { m_locationStack.push(m_current); visitProBlock(pro, pro->tokPtr()); diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index e455fb3858..b555102bf8 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -268,13 +268,13 @@ void QMakeEvaluator::skipHashStr(const ushort *&tokPtr) // FIXME: this should not build new strings for direct sections. // Note that the E_SPRINTF and E_LIST implementations rely on the deep copy. -ProStringList QMakeEvaluator::split_value_list(const QStringRef &vals, const ProFile *source) +ProStringList QMakeEvaluator::split_value_list(const QStringRef &vals, int source) { QString build; ProStringList ret; if (!source) - source = currentProFile(); + source = currentFileId(); const QChar *vals_data = vals.data(); const int vals_len = vals.length(); @@ -1311,7 +1311,7 @@ void QMakeEvaluator::setupProject() { setTemplate(); ProValueMap &vars = m_valuemapStack.top(); - ProFile *proFile = currentProFile(); + int proFile = currentFileId(); vars[ProKey("TARGET")] << ProString(QFileInfo(currentFileName()).baseName()).setSource(proFile); vars[ProKey("_PRO_FILE_")] << ProString(currentFileName()).setSource(proFile); vars[ProKey("_PRO_FILE_PWD_")] << ProString(currentDirectory()).setSource(proFile); @@ -1321,7 +1321,7 @@ void QMakeEvaluator::setupProject() void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where) { if (!cmds.isEmpty()) { - ProFile *pro = m_parser->parsedProBlock(QStringRef(&cmds), where, -1); + ProFile *pro = m_parser->parsedProBlock(QStringRef(&cmds), 0, where, -1); if (pro->isOk()) { m_locationStack.push(m_current); visitProBlock(pro, pro->tokPtr()); @@ -1605,6 +1605,14 @@ ProFile *QMakeEvaluator::currentProFile() const return 0; } +int QMakeEvaluator::currentFileId() const +{ + ProFile *pro = currentProFile(); + if (pro) + return pro->id(); + return 0; +} + QString QMakeEvaluator::currentFileName() const { ProFile *pro = currentProFile(); @@ -1819,7 +1827,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditional( const QStringRef &cond, const QString &where, int line) { VisitReturn ret = ReturnFalse; - ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar); + ProFile *pro = m_parser->parsedProBlock(cond, 0, where, line, QMakeParser::TestGrammar); if (pro->isOk()) { m_locationStack.push(m_current); ret = visitProBlock(pro, pro->tokPtr()); diff --git a/src/shared/proparser/qmakeevaluator.h b/src/shared/proparser/qmakeevaluator.h index a2ba21025f..c39b8abcde 100644 --- a/src/shared/proparser/qmakeevaluator.h +++ b/src/shared/proparser/qmakeevaluator.h @@ -173,12 +173,13 @@ public: void setTemplate(); - ProStringList split_value_list(const QStringRef &vals, const ProFile *source = 0); + ProStringList split_value_list(const QStringRef &vals, int source = 0); VisitReturn expandVariableReferences(const ushort *&tokPtr, int sizeHint, ProStringList *ret, bool joined); QString currentFileName() const; QString currentDirectory() const; ProFile *currentProFile() const; + int currentFileId() const; QString resolvePath(const QString &fileName) const { return QMakeInternal::IoUtils::resolvePath(currentDirectory(), fileName); } diff --git a/src/shared/proparser/qmakeparser.cpp b/src/shared/proparser/qmakeparser.cpp index a9a1b6d9a7..6b0ae22e83 100644 --- a/src/shared/proparser/qmakeparser.cpp +++ b/src/shared/proparser/qmakeparser.cpp @@ -49,12 +49,22 @@ ProFileCache::~ProFileCache() ent.pro->deref(); } -void ProFileCache::discardFile(const QString &fileName) +void ProFileCache::discardFile(const QString &fileName, QMakeVfs *vfs) +{ + int eid = vfs->idForFileName(fileName, QMakeVfs::VfsExact | QMakeVfs::VfsAccessedOnly); + if (eid) + discardFile(eid); + int cid = vfs->idForFileName(fileName, QMakeVfs::VfsCumulative | QMakeVfs::VfsAccessedOnly); + if (cid && cid != eid) + discardFile(cid); +} + +void ProFileCache::discardFile(int id) { #ifdef PROPARSER_THREAD_SAFE QMutexLocker lck(&mutex); #endif - QHash<QString, Entry>::Iterator it = parsed_files.find(fileName); + auto it = parsed_files.find(id); if (it != parsed_files.end()) { #ifdef PROPARSER_THREAD_SAFE if (it->locker) { @@ -74,16 +84,16 @@ void ProFileCache::discardFile(const QString &fileName) } } -void ProFileCache::discardFiles(const QString &prefix) +void ProFileCache::discardFiles(const QString &prefix, QMakeVfs *vfs) { #ifdef PROPARSER_THREAD_SAFE QMutexLocker lck(&mutex); #endif - QHash<QString, Entry>::Iterator - it = parsed_files.begin(), - end = parsed_files.end(); - while (it != end) - if (it.key().startsWith(prefix)) { + auto it = parsed_files.begin(), end = parsed_files.end(); + while (it != end) { + // Note: this is empty for virtual files from other VFSes. + QString fn = vfs->fileNameForId(it.key()); + if (fn.startsWith(prefix)) { #ifdef PROPARSER_THREAD_SAFE if (it->locker) { if (!it->locker->done) { @@ -102,6 +112,7 @@ void ProFileCache::discardFiles(const QString &prefix) } else { ++it; } + } } ////////// Parser /////////// @@ -164,18 +175,15 @@ QMakeParser::QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) { ProFile *pro; - if ((flags & (ParseUseCache|ParseOnlyCached)) && m_cache) { + QMakeVfs::VfsFlags vfsFlags = ((flags & ParseCumulative) ? QMakeVfs::VfsCumulative + : QMakeVfs::VfsExact); + int id = m_vfs->idForFileName(fileName, vfsFlags); + if ((flags & ParseUseCache) && m_cache) { ProFileCache::Entry *ent; #ifdef PROPARSER_THREAD_SAFE QMutexLocker locker(&m_cache->mutex); #endif - QHash<QString, ProFileCache::Entry>::Iterator it; -#ifdef PROEVALUATOR_DUAL_VFS - QString virtFileName = ((flags & ParseCumulative) ? '-' : '+') + fileName; - it = m_cache->parsed_files.find(virtFileName); - if (it == m_cache->parsed_files.end()) -#endif - it = m_cache->parsed_files.find(fileName); + auto it = m_cache->parsed_files.find(id); if (it != m_cache->parsed_files.end()) { ent = &*it; #ifdef PROPARSER_THREAD_SAFE @@ -192,24 +200,15 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) #endif if ((pro = ent->pro)) pro->ref(); - } else if (!(flags & ParseOnlyCached)) { - QString contents; - QMakeVfs::VfsFlags vfsFlags = - ((flags & ParseCumulative) ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact); - bool virt = false; -#ifdef PROEVALUATOR_DUAL_VFS - virt = m_vfs->readVirtualFile(fileName, vfsFlags, &contents); - if (virt) - ent = &m_cache->parsed_files[virtFileName]; - else -#endif - ent = &m_cache->parsed_files[fileName]; + } else { + ent = &m_cache->parsed_files[id]; #ifdef PROPARSER_THREAD_SAFE ent->locker = new ProFileCache::Entry::Locker; locker.unlock(); #endif - if (virt || readFile(fileName, vfsFlags | QMakeVfs::VfsNoVirtual, flags, &contents)) { - pro = parsedProBlock(QStringRef(&contents), fileName, 1, FullGrammar); + QString contents; + if (readFile(id, flags, &contents)) { + pro = parsedProBlock(QStringRef(&contents), id, fileName, 1, FullGrammar); pro->itemsRef()->squeeze(); pro->ref(); } else { @@ -226,46 +225,39 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) ent->locker = 0; } #endif - } else { - pro = 0; } - } else if (!(flags & ParseOnlyCached)) { + } else { QString contents; - QMakeVfs::VfsFlags vfsFlags = - ((flags & ParseCumulative) ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact); - if (readFile(fileName, vfsFlags, flags, &contents)) - pro = parsedProBlock(QStringRef(&contents), fileName, 1, FullGrammar); + if (readFile(id, flags, &contents)) + pro = parsedProBlock(QStringRef(&contents), id, fileName, 1, FullGrammar); else pro = 0; - } else { - pro = 0; } return pro; } ProFile *QMakeParser::parsedProBlock( - const QStringRef &contents, const QString &name, int line, SubGrammar grammar) + const QStringRef &contents, int id, const QString &name, int line, SubGrammar grammar) { - ProFile *pro = new ProFile(name); + ProFile *pro = new ProFile(id, name); read(pro, contents, line, grammar); return pro; } -void QMakeParser::discardFileFromCache(const QString &fileName) +void QMakeParser::discardFileFromCache(int id) { if (m_cache) - m_cache->discardFile(fileName); + m_cache->discardFile(id); } -bool QMakeParser::readFile( - const QString &fn, QMakeVfs::VfsFlags vfsFlags, ParseFlags flags, QString *contents) +bool QMakeParser::readFile(int id, ParseFlags flags, QString *contents) { QString errStr; - QMakeVfs::ReadResult result = m_vfs->readFile(fn, vfsFlags, contents, &errStr); + QMakeVfs::ReadResult result = m_vfs->readFile(id, contents, &errStr); if (result != QMakeVfs::ReadOk) { if (m_handler && ((flags & ParseReportMissing) || result != QMakeVfs::ReadNotFound)) m_handler->message(QMakeParserHandler::ParserIoError, - fL1S("Cannot read %1: %2").arg(fn, errStr)); + fL1S("Cannot read %1: %2").arg(m_vfs->fileNameForId(id), errStr)); return false; } return true; diff --git a/src/shared/proparser/qmakeparser.h b/src/shared/proparser/qmakeparser.h index 43fa354b9e..0612b92262 100644 --- a/src/shared/proparser/qmakeparser.h +++ b/src/shared/proparser/qmakeparser.h @@ -75,7 +75,6 @@ public: enum ParseFlag { ParseDefault = 0, ParseUseCache = 1, - ParseOnlyCached = 2, ParseReportMissing = 4, #ifdef PROEVALUATOR_DUAL_VFS ParseCumulative = 8 @@ -90,10 +89,10 @@ public: enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar }; // fileName is expected to be absolute and cleanPath()ed. ProFile *parsedProFile(const QString &fileName, ParseFlags flags = ParseDefault); - ProFile *parsedProBlock(const QStringRef &contents, const QString &name, int line = 0, + ProFile *parsedProBlock(const QStringRef &contents, int id, const QString &name, int line = 0, SubGrammar grammar = FullGrammar); - void discardFileFromCache(const QString &fileName); + void discardFileFromCache(int id); #ifdef PROPARSER_DEBUG static QString formatProBlock(const QString &block); @@ -132,7 +131,7 @@ private: ushort terminator; // '}' if replace function call is braced, ':' if test function }; - bool readFile(const QString &fn, QMakeVfs::VfsFlags vfsFlags, QMakeParser::ParseFlags flags, QString *contents); + bool readFile(int id, QMakeParser::ParseFlags flags, QString *contents); void read(ProFile *pro, const QStringRef &content, int line, SubGrammar grammar); ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok); @@ -201,8 +200,9 @@ public: ProFileCache() {} ~ProFileCache(); - void discardFile(const QString &fileName); - void discardFiles(const QString &prefix); + void discardFile(int id); + void discardFile(const QString &fileName, QMakeVfs *vfs); + void discardFiles(const QString &prefix, QMakeVfs *vfs); private: struct Entry { @@ -218,7 +218,7 @@ private: #endif }; - QHash<QString, Entry> parsed_files; + QHash<int, Entry> parsed_files; #ifdef PROPARSER_THREAD_SAFE QMutex mutex; #endif diff --git a/src/shared/proparser/qmakevfs.cpp b/src/shared/proparser/qmakevfs.cpp index 4dd1192aff..d7248fbd5b 100644 --- a/src/shared/proparser/qmakevfs.cpp +++ b/src/shared/proparser/qmakevfs.cpp @@ -51,19 +51,85 @@ QMakeVfs::QMakeVfs() #endif } -bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, VfsFlags flags, +#ifdef PROPARSER_THREAD_SAFE +QMutex QMakeVfs::s_mutex; +#endif +QAtomicInt QMakeVfs::s_fileIdCounter; +QHash<QString, int> QMakeVfs::s_fileIdMap; +QHash<int, QString> QMakeVfs::s_idFileMap; + +int QMakeVfs::idForFileName(const QString &fn, VfsFlags flags) +{ +#ifdef PROEVALUATOR_DUAL_VFS + { +# ifdef PROPARSER_THREAD_SAFE + QMutexLocker locker(&m_vmutex); +# endif + int idx = (flags & VfsCumulative) ? 1 : 0; + if (flags & VfsCreate) { + int &id = m_virtualFileIdMap[idx][fn]; + if (!id) { + id = ++s_fileIdCounter; + m_virtualIdFileMap[id] = fn; + } + return id; + } + int id = m_virtualFileIdMap[idx].value(fn); + if (id || (flags & VfsCreatedOnly)) + return id; + } +#endif + if (!(flags & VfsAccessedOnly)) { +#ifdef PROPARSER_THREAD_SAFE + QMutexLocker locker(&s_mutex); +#endif + int &id = s_fileIdMap[fn]; + if (!id) { + id = ++s_fileIdCounter; + s_idFileMap[id] = fn; + } + return id; + } + return s_fileIdMap.value(fn); +} + +QString QMakeVfs::fileNameForId(int id) +{ +#ifdef PROEVALUATOR_DUAL_VFS + { +# ifdef PROPARSER_THREAD_SAFE + QMutexLocker locker(&m_vmutex); +# endif + const QString &fn = m_virtualIdFileMap.value(id); + if (!fn.isEmpty()) + return fn; + } +#endif +#ifdef PROPARSER_THREAD_SAFE + QMutexLocker locker(&s_mutex); +#endif + return s_idFileMap.value(id); +} + +void QMakeVfs::clearIds() +{ +#ifdef PROEVALUATOR_THREAD_SAFE + QMutexLocker locker(&s_mutex); +#endif + s_fileIdCounter = 0; + s_fileIdMap.clear(); + s_idFileMap.clear(); +} + +bool QMakeVfs::writeFile(int id, QIODevice::OpenMode mode, VfsFlags flags, const QString &contents, QString *errStr) { #ifndef PROEVALUATOR_FULL # ifdef PROEVALUATOR_THREAD_SAFE QMutexLocker locker(&m_mutex); # endif -#ifdef PROEVALUATOR_DUAL_VFS - QString *cont = &m_files[((flags & VfsCumulative) ? '-' : '+') + fn]; -#else - QString *cont = &m_files[fn]; + QString *cont = &m_files[id]; Q_UNUSED(flags) -#endif if (mode & QIODevice::Append) *cont += contents; else @@ -71,13 +137,13 @@ bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, VfsFlags f Q_UNUSED(errStr) return true; #else - QFileInfo qfi(fn); + QFileInfo qfi(fileNameForId(id)); if (!QDir::current().mkpath(qfi.path())) { *errStr = fL1S("Cannot create parent directory"); return false; } QByteArray bytes = contents.toLocal8Bit(); - QFile cfile(fn); + QFile cfile(qfi.filePath()); if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) { if (cfile.readAll() == bytes) { if (flags & VfsExecutable) { @@ -108,53 +174,13 @@ bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, VfsFlags f #endif } -#ifndef PROEVALUATOR_FULL -bool QMakeVfs::readVirtualFile(const QString &fn, VfsFlags flags, QString *contents) -{ -# ifdef PROEVALUATOR_THREAD_SAFE - QMutexLocker locker(&m_mutex); -# endif - QHash<QString, QString>::ConstIterator it; -# ifdef PROEVALUATOR_DUAL_VFS - it = m_files.constFind(((flags & VfsCumulative) ? '-' : '+') + fn); - if (it != m_files.constEnd()) { - *contents = *it; - return true; - } -# else - it = m_files.constFind(fn); - if (it != m_files.constEnd() - && it->constData() != m_magicMissing.constData() - && it->constData() != m_magicExisting.constData()) { - *contents = *it; - return true; - } - Q_UNUSED(flags) -# endif - return false; -} -#endif - -QMakeVfs::ReadResult QMakeVfs::readFile( - const QString &fn, VfsFlags flags, QString *contents, QString *errStr) +QMakeVfs::ReadResult QMakeVfs::readFile(int id, QString *contents, QString *errStr) { #ifndef PROEVALUATOR_FULL # ifdef PROEVALUATOR_THREAD_SAFE QMutexLocker locker(&m_mutex); # endif - QHash<QString, QString>::ConstIterator it; -# ifdef PROEVALUATOR_DUAL_VFS - if (!(flags & VfsNoVirtual)) { - it = m_files.constFind(((flags & VfsCumulative) ? '-' : '+') + fn); - if (it != m_files.constEnd()) { - *contents = *it; - return ReadOk; - } - } -# else - Q_UNUSED(flags) -# endif - it = m_files.constFind(fn); + auto it = m_files.constFind(id); if (it != m_files.constEnd()) { if (it->constData() == m_magicMissing.constData()) { *errStr = fL1S("No such file or directory"); @@ -165,15 +191,13 @@ QMakeVfs::ReadResult QMakeVfs::readFile( return ReadOk; } } -#else - Q_UNUSED(flags) #endif - QFile file(fn); + QFile file(fileNameForId(id)); if (!file.open(QIODevice::ReadOnly)) { if (!file.exists()) { #ifndef PROEVALUATOR_FULL - m_files[fn] = m_magicMissing; + m_files[id] = m_magicMissing; #endif *errStr = fL1S("No such file or directory"); return ReadNotFound; @@ -182,7 +206,7 @@ QMakeVfs::ReadResult QMakeVfs::readFile( return ReadOtherError; } #ifndef PROEVALUATOR_FULL - m_files[fn] = m_magicExisting; + m_files[id] = m_magicExisting; #endif QByteArray bcont = file.readAll(); @@ -205,15 +229,8 @@ bool QMakeVfs::exists(const QString &fn, VfsFlags flags) # ifdef PROEVALUATOR_THREAD_SAFE QMutexLocker locker(&m_mutex); # endif - QHash<QString, QString>::ConstIterator it; -# ifdef PROEVALUATOR_DUAL_VFS - it = m_files.constFind(((flags & VfsCumulative) ? '-' : '+') + fn); - if (it != m_files.constEnd()) - return true; -# else - Q_UNUSED(flags) -# endif - it = m_files.constFind(fn); + int id = idForFileName(fn, flags); + auto it = m_files.constFind(id); if (it != m_files.constEnd()) return it->constData() != m_magicMissing.constData(); #else @@ -221,7 +238,7 @@ bool QMakeVfs::exists(const QString &fn, VfsFlags flags) #endif bool ex = IoUtils::fileType(fn) == IoUtils::FileIsRegular; #ifndef PROEVALUATOR_FULL - m_files[fn] = ex ? m_magicExisting : m_magicMissing; + m_files[id] = ex ? m_magicExisting : m_magicMissing; #endif return ex; } @@ -233,7 +250,7 @@ void QMakeVfs::invalidateCache() # ifdef PROEVALUATOR_THREAD_SAFE QMutexLocker locker(&m_mutex); # endif - QHash<QString, QString>::Iterator it = m_files.begin(), eit = m_files.end(); + auto it = m_files.begin(), eit = m_files.end(); while (it != eit) { if (it->constData() == m_magicMissing.constData() ||it->constData() == m_magicExisting.constData()) diff --git a/src/shared/proparser/qmakevfs.h b/src/shared/proparser/qmakevfs.h index b6b93fb5dd..da0d0626d8 100644 --- a/src/shared/proparser/qmakevfs.h +++ b/src/shared/proparser/qmakevfs.h @@ -27,13 +27,11 @@ #include "qmake_global.h" -# include <qiodevice.h> -#ifndef PROEVALUATOR_FULL -# include <qhash.h> -# include <qstring.h> -# ifdef PROEVALUATOR_THREAD_SAFE -# include <qmutex.h> -# endif +#include <qiodevice.h> +#include <qhash.h> +#include <qstring.h> +#ifdef PROEVALUATOR_THREAD_SAFE +# include <qmutex.h> #endif #ifndef QT_NO_TEXTCODEC @@ -62,23 +60,27 @@ public: VfsExact = 0, #ifdef PROEVALUATOR_DUAL_VFS VfsCumulative = 2, - VfsNoVirtual = 4 + VfsCreate = 4, + VfsCreatedOnly = 8, #else VfsCumulative = 0, - VfsNoVirtual = 0 + VfsCreate = 0, + VfsCreatedOnly = 0, #endif + VfsAccessedOnly = 16 }; Q_DECLARE_FLAGS(VfsFlags, VfsFlag) QMakeVfs(); - bool writeFile(const QString &fn, QIODevice::OpenMode mode, VfsFlags flags, const QString &contents, QString *errStr); - ReadResult readFile(const QString &fn, VfsFlags flags, QString *contents, QString *errStr); - bool exists(const QString &fn, VfsFlags flags); + int idForFileName(const QString &fn, VfsFlags flags); + QString fileNameForId(int id); + static void clearIds(); + bool writeFile(int id, QIODevice::OpenMode mode, VfsFlags flags, const QString &contents, QString *errStr); + ReadResult readFile(int id, QString *contents, QString *errStr); + bool exists(const QString &fn, QMakeVfs::VfsFlags flags); #ifndef PROEVALUATOR_FULL - bool readVirtualFile(const QString &fn, VfsFlags flags, QString *contents); - void invalidateCache(); void invalidateContents(); #endif @@ -88,11 +90,34 @@ public: #endif private: +#ifdef PROEVALUATOR_THREAD_SAFE + static QMutex s_mutex; +#endif + static QAtomicInt s_fileIdCounter; + // Qt Creator's ProFile cache is a singleton to maximize its cross-project + // effectiveness (shared prf files from QtVersions). + // For this to actually work, real files need a global mapping. + // This is fine, because the namespace of real files is indeed global. + static QHash<QString, int> s_fileIdMap; + static QHash<int, QString> s_idFileMap; +#ifdef PROEVALUATOR_DUAL_VFS +# ifdef PROEVALUATOR_THREAD_SAFE + // The simple way to avoid recursing m_mutex. + QMutex m_vmutex; +# endif + // Virtual files are bound to the project context they were created in, + // so their ids need to be local as well. + // We violate that rule in lupdate (which has a non-dual VFS), but that + // does not matter, because it has only one project context anyway. + QHash<QString, int> m_virtualFileIdMap[2]; // Exact and cumulative + QHash<int, QString> m_virtualIdFileMap; // Only one map, as ids are unique across realms. +#endif + #ifndef PROEVALUATOR_FULL # ifdef PROEVALUATOR_THREAD_SAFE QMutex m_mutex; # endif - QHash<QString, QString> m_files; + QHash<int, QString> m_files; QString m_magicMissing; QString m_magicExisting; #endif |