diff --git a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp index d2fc8051dec..e02c037aa1d 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp @@ -145,13 +145,13 @@ static void createTree(const QmakePriFile *pri, QmakePriFileNode *node, const Fi const auto proFile = dynamic_cast(pri); for (int i = 0; i < fileTypes.size(); ++i) { FileType type = fileTypes.at(i).type; - const QSet &newFilePaths = Utils::filtered(pri->files(type), [&toExclude](const Utils::FilePath &fn) { - return !Utils::contains(toExclude, [&fn](const Utils::FilePath &ex) { return fn.isChildOf(ex); }); + const SourceFiles &newFilePaths = Utils::filtered(pri->files(type), [&toExclude](const SourceFile &fn) { + return !Utils::contains(toExclude, [&fn](const Utils::FilePath &ex) { return fn.first.isChildOf(ex); }); }); if (proFile) { - for (const FilePath &fp : newFilePaths) { + for (const SourceFile &fp : newFilePaths) { for (const ExtraCompiler *ec : proFile->extraCompilers()) { - if (ec->source() == fp) + if (ec->source() == fp.first) generatedFiles << ec->targets(); } } @@ -165,33 +165,36 @@ static void createTree(const QmakePriFile *pri, QmakePriFileNode *node, const Fi vfolder->setAddFileFilter(fileTypes.at(i).addFileFilter); if (type == FileType::Resource) { - for (const FilePath &file : newFilePaths) { + for (const auto &file : newFilePaths) { auto vfs = pri->project()->qmakeVfs(); QString contents; QString errorMessage; // Prefer the cumulative file if it's non-empty, based on the assumption // that it contains more "stuff". - int cid = vfs->idForFileName(file.toString(), QMakeVfs::VfsCumulative); + int cid = vfs->idForFileName(file.first.toString(), QMakeVfs::VfsCumulative); vfs->readFile(cid, &contents, &errorMessage); // If the cumulative evaluation botched the file too much, try the exact one. if (contents.isEmpty()) { - int eid = vfs->idForFileName(file.toString(), QMakeVfs::VfsExact); + int eid = vfs->idForFileName(file.first.toString(), QMakeVfs::VfsExact); vfs->readFile(eid, &contents, &errorMessage); } auto topLevel = std::make_unique - (file, vfolder->filePath(), contents); - const QString baseName = file.toFileInfo().completeBaseName(); + (file.first, vfolder->filePath(), contents); + topLevel->setEnabled(file.second == FileOrigin::ExactParse); + const QString baseName = file.first.toFileInfo().completeBaseName(); topLevel->setIsGenerated(baseName.startsWith("qmake_") || baseName.endsWith("_qmlcache")); vfolder->addNode(std::move(topLevel)); } } else { - for (const FilePath &fn : newFilePaths) { + for (const auto &fn : newFilePaths) { // Qmake will flag everything in SOURCES as source, even when the // qt quick compiler moves qrc files into it:-/ Get better data based on // the filename. - type = FileNode::fileTypeForFileName(fn); - vfolder->addNestedNode(std::make_unique(fn, type)); + type = FileNode::fileTypeForFileName(fn.first); + auto fileNode = std::make_unique(fn.first, type); + fileNode->setEnabled(fn.second == FileOrigin::ExactParse); + vfolder->addNestedNode(std::move(fileNode)); } for (FolderNode *fn : vfolder->folderNodes()) fn->compress(); diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index 85d6d4a7c23..fc3be830c71 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -103,6 +103,7 @@ namespace QmakeProjectManager { Q_LOGGING_CATEGORY(qmakeParse, "qtc.qmake.parsing", QtWarningMsg); uint qHash(Variable key, uint seed) { return ::qHash(static_cast(key), seed); } +uint qHash(FileOrigin fo) { return ::qHash(int(fo)); } namespace Internal { @@ -124,7 +125,8 @@ class QmakePriFileEvalResult public: QSet folders; QSet recursiveEnumerateFiles; - QMap> foundFiles; + QMap> foundFilesExact; + QMap> foundFilesCumulative; }; class QmakeIncludedPriFile @@ -228,14 +230,15 @@ void QmakePriFile::makeEmpty() m_children.clear(); } -QSet QmakePriFile::files(const FileType &type) const +SourceFiles QmakePriFile::files(const FileType &type) const { return m_files.value(type); } const QSet QmakePriFile::collectFiles(const FileType &type) const { - QSet allFiles = files(type); + QSet allFiles = transform(files(type), + [](const SourceFile &sf) { return sf.first; }); for (const QmakePriFile * const priFile : qAsConst(m_children)) { if (!dynamic_cast(priFile)) allFiles.unite(priFile->collectFiles(type)); @@ -308,13 +311,14 @@ static QStringList fileListForVar( void QmakePriFile::extractSources( QHash proToResult, QmakePriFileEvalResult *fallback, - QVector sourceFiles, FileType type) + QVector sourceFiles, FileType type, bool cumulative) { foreach (const ProFileEvaluator::SourceFile &source, sourceFiles) { auto *result = proToResult.value(source.proFileId); if (!result) result = fallback; - result->foundFiles[type].insert(FilePath::fromString(source.fileName)); + auto &foundFiles = cumulative ? result->foundFilesCumulative : result->foundFilesExact; + foundFiles[type].insert(FilePath::fromString(source.fileName)); } } @@ -356,11 +360,13 @@ void QmakePriFile::processValues(QmakePriFileEvalResult &result) for (int i = 0; i < static_cast(FileType::FileTypeSize); ++i) { auto type = static_cast(i); - QSet &foundFiles = result.foundFiles[type]; - result.recursiveEnumerateFiles.subtract(foundFiles); - QSet newFilePaths = filterFilesProVariables(type, foundFiles); - newFilePaths += filterFilesRecursiveEnumerata(type, result.recursiveEnumerateFiles); - foundFiles = newFilePaths; + for (QSet * const foundFiles + : {&result.foundFilesExact[type], &result.foundFilesCumulative[type]}) { + result.recursiveEnumerateFiles.subtract(*foundFiles); + QSet newFilePaths = filterFilesProVariables(type, *foundFiles); + newFilePaths += filterFilesRecursiveEnumerata(type, result.recursiveEnumerateFiles); + *foundFiles = newFilePaths; + } } } @@ -371,7 +377,15 @@ void QmakePriFile::update(const Internal::QmakePriFileEvalResult &result) for (int i = 0; i < static_cast(FileType::FileTypeSize); ++i) { const auto type = static_cast(i); - m_files[type] = result.foundFiles.value(type); + SourceFiles &files = m_files[type]; + files.clear(); + const QSet exactFps = result.foundFilesExact.value(type); + for (const FilePath &exactFp : exactFps) + files << qMakePair(exactFp, FileOrigin::ExactParse); + for (const FilePath &cumulativeFp : result.foundFilesCumulative.value(type)) { + if (!exactFps.contains(cumulativeFp)) + files << qMakePair(cumulativeFp, FileOrigin::CumulativeParse); + } } } @@ -439,9 +453,18 @@ bool QmakePriFile::folderChanged(const QString &changedFolder, const QSet(type) <<"\n" << "added files" << add << "\n" << "removed files" << remove; - - m_files[type].unite(add); - m_files[type].subtract(remove); + SourceFiles ¤tFiles = m_files[type]; + for (const FilePath &fp : add) { + if (!contains(currentFiles, [&fp](const SourceFile &sf) { return sf.first == fp; })) + currentFiles.insert(qMakePair(fp, FileOrigin::ExactParse)); + } + for (const FilePath &fp : remove) { + const auto it = std::find_if(currentFiles.begin(), currentFiles.end(), + [&fp](const SourceFile &sf) { + return sf.first == fp; }); + if (it != currentFiles.end()) + currentFiles.erase(it); + } } } return true; @@ -1451,14 +1474,14 @@ QmakeEvalResult *QmakeProFile::evaluate(const QmakeEvalInput &input) auto sourceFiles = exactReader->absoluteFileValues( qmakeVariable, input.projectDir, vPathsExact, &handled, result->directoriesWithWildcards); exactSourceFiles[qmakeVariable] = sourceFiles; - extractSources(proToResult, &result->includedFiles.result, sourceFiles, type); + extractSources(proToResult, &result->includedFiles.result, sourceFiles, type, false); } const QStringList vPathsCumulative = fullVPaths( baseVPathsCumulative, cumulativeReader, qmakeVariable, input.projectDir); auto sourceFiles = cumulativeReader->absoluteFileValues( qmakeVariable, input.projectDir, vPathsCumulative, &handled, result->directoriesWithWildcards); cumulativeSourceFiles[qmakeVariable] = sourceFiles; - extractSources(proToResult, &result->includedFiles.result, sourceFiles, type); + extractSources(proToResult, &result->includedFiles.result, sourceFiles, type, true); } } diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h index 94eaffe267d..a6e7fa4ad56 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h @@ -33,10 +33,11 @@ #include #include -#include -#include -#include #include +#include +#include +#include +#include #include @@ -112,6 +113,11 @@ class QmakePriFileEvalResult; class InstallsList; +enum class FileOrigin { ExactParse, CumulativeParse }; +uint qHash(FileOrigin fo); +using SourceFile = QPair; +using SourceFiles = QSet; + // Implements ProjectNode for qmake .pri files class QMAKEPROJECTMANAGER_EXPORT QmakePriFile { @@ -135,7 +141,7 @@ public: void makeEmpty(); // Files of the specified type declared in this file. - QSet files(const ProjectExplorer::FileType &type) const; + SourceFiles files(const ProjectExplorer::FileType &type) const; // Files of the specified type declared in this file and in included .pri files. const QSet collectFiles(const ProjectExplorer::FileType &type) const; @@ -210,10 +216,9 @@ private: QStringList formResources(const QString &formFile) const; 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 proToResult, + static void extractSources(QHash proToResult, Internal::QmakePriFileEvalResult *fallback, - QVector sourceFiles, ProjectExplorer::FileType type); + QVector sourceFiles, ProjectExplorer::FileType type, bool cumulative); static void extractInstalls( QHash proToResult, Internal::QmakePriFileEvalResult *fallback, @@ -232,7 +237,7 @@ private: Utils::TextFileFormat m_textFormat; // Memory is cheap... - QMap> m_files; + QMap m_files; QSet m_recursiveEnumerateFiles; // FIXME: Remove this?! QSet m_watchedFolders; bool m_includedInExactParse = true;