From ac37c5c9502a8e137542ea399b4a002c3b3cf628 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 20 Aug 2019 14:48:48 +0200 Subject: [PATCH] QmakeProjectManager: Mark disabled source files in project tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We show all source files in the project tree, including those which are listed in scopes that evaluate to false in the current configuration. This is intended, as we want users to be able to navigate to all files, not just the ones that are part of the build for the current target. However, it'd be nice for users to be able to tell which files are "active" and which ones are not. Therefore, we now mark the non-active ones as "disabled" in the project tree, just like the QbsProjectManager does. Task-number: QTCREATORBUG-22855 Change-Id: Icfb48d4f6a247de76fc109acb84b34f03866e754 Reviewed-by: Jörg Bornemann --- .../qmakenodetreebuilder.cpp | 27 +++++---- .../qmakeprojectmanager/qmakeparsernodes.cpp | 55 +++++++++++++------ .../qmakeprojectmanager/qmakeparsernodes.h | 21 ++++--- 3 files changed, 67 insertions(+), 36 deletions(-) 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;