From 53115259baa522d0d2d8f05aaa058693b1de62a8 Mon Sep 17 00:00:00 2001 From: Dmitriy Purgin Date: Mon, 26 Oct 2020 15:36:59 +0100 Subject: [PATCH] CMakeProjectManager: Add File System virtual folder If a CMake project cannot be parsed by CMake, it is practically unusable in Qt Creator. According to discussion in QTCREATORBUG-24677, a virtual folder with the project's file system view is added to the project manager as a convenience feature. Fixes: QTCREATORBUG-24677 Change-Id: I48775bb89c704d3f7e5bb21ec6481bd5cc0f4b6c Reviewed-by: hjk Reviewed-by: Kai Koehne Reviewed-by: Eike Ziller --- .../cmakeprojectmanager/cmakebuildsystem.cpp | 22 +++++++++++++--- .../cmakeprojectmanager/cmakebuildsystem.h | 4 +-- .../fileapidataextractor.cpp | 24 +++++++++++++++++ .../fileapidataextractor.h | 5 ++++ .../cmakeprojectmanager/fileapireader.cpp | 21 ++++++++++----- .../cmakeprojectmanager/fileapireader.h | 4 ++- .../cmakeprojectmanager/projecttreehelper.cpp | 26 +++++++++++++++++++ .../cmakeprojectmanager/projecttreehelper.h | 2 ++ 8 files changed, 94 insertions(+), 14 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 01706f7a082..109051fe0ea 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -517,11 +517,11 @@ void CMakeBuildSystem::clearCMakeCache() Utils::FileUtils::removeRecursively(cmakeFiles); } -std::unique_ptr - CMakeBuildSystem::generateProjectTree(const QList &allFiles) +std::unique_ptr CMakeBuildSystem::generateProjectTree( + const QList &allFiles, bool includeHeaderNodes) { QString errorMessage; - auto root = m_reader.generateProjectTree(allFiles, errorMessage); + auto root = m_reader.generateProjectTree(allFiles, errorMessage, includeHeaderNodes); checkAndReportError(errorMessage); return root; } @@ -535,6 +535,8 @@ void CMakeBuildSystem::combineScanAndParse() if (m_combinedScanAndParseResult) { updateProjectData(); m_currentGuard.markAsSuccess(); + } else { + updateFallbackProjectData(); } } @@ -590,7 +592,7 @@ void CMakeBuildSystem::updateProjectData() Project *p = project(); { - auto newRoot = generateProjectTree(m_allFiles); + auto newRoot = generateProjectTree(m_allFiles, true); if (newRoot) { setRootProjectNode(std::move(newRoot)); CMakeConfigItem settingFileItem; @@ -671,6 +673,18 @@ void CMakeBuildSystem::updateProjectData() qCDebug(cmakeBuildSystemLog) << "All CMake project data up to date."; } +void CMakeBuildSystem::updateFallbackProjectData() +{ + qCDebug(cmakeBuildSystemLog) << "Updating fallback CMake project data"; + + QTC_ASSERT(m_treeScanner.isFinished() && !m_reader.isParsing(), return ); + + auto newRoot = generateProjectTree(m_allFiles, false); + setRootProjectNode(std::move(newRoot)); + + qCDebug(cmakeBuildSystemLog) << "All fallback CMake project data up to date."; +} + void CMakeBuildSystem::handleParsingSucceeded() { if (!cmakeBuildConfiguration()->isActive()) { diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index e4c69a7d3c1..ccc0a2e9342 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -123,11 +123,11 @@ private: void combineScanAndParse(); std::unique_ptr generateProjectTree( - const QList &allFiles); - + const QList &allFiles, bool includeHeadersNode); void checkAndReportError(QString &errorMessage); void updateProjectData(); + void updateFallbackProjectData(); QList findExtraCompilers(); void updateQmlJSCodeModel(); diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index 08937953f12..eea97ed04fd 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -692,5 +692,29 @@ FileApiQtcData extractData(FileApiData &input, return result; } +FileApiQtcData generateFallbackData(const FilePath &topCmakeFile, + const FilePath &sourceDirectory, + const FilePath &buildDirectory, + QString errorMessage) +{ + FileApiQtcData result; + + result.rootProjectNode.reset(new CMakeProjectNode{sourceDirectory}); + result.rootProjectNode->setDisplayName(sourceDirectory.fileName()); + result.errorMessage = errorMessage; + + if (!topCmakeFile.isEmpty()) { + auto node = std::make_unique(topCmakeFile, FileType::Project); + node->setIsGenerated(false); + + std::vector> fileNodes; + fileNodes.emplace_back(std::move(node)); + + addCMakeLists(result.rootProjectNode.get(), std::move(fileNodes)); + } + + return result; +} + } // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.h b/src/plugins/cmakeprojectmanager/fileapidataextractor.h index f89da90296c..9db433765d8 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.h +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.h @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -58,6 +59,10 @@ public: FileApiQtcData extractData(FileApiData &data, const Utils::FilePath &sourceDirectory, const Utils::FilePath &buildDirectory); +FileApiQtcData generateFallbackData(const Utils::FilePath &topCmakeFile, + const Utils::FilePath &sourceDirectory, + const Utils::FilePath &buildDirectory, + QString errorMessage); } // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp index 1e25125a80a..75cf51a9868 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.cpp +++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp @@ -193,11 +193,14 @@ CMakeConfig FileApiReader::takeParsedConfiguration(QString &errorMessage) } std::unique_ptr FileApiReader::generateProjectTree( - const QList &allFiles, QString &errorMessage) + const QList &allFiles, QString &errorMessage, bool includeHeaderNodes) { Q_UNUSED(errorMessage) - addHeaderNodes(m_rootProjectNode.get(), m_knownHeaders, allFiles); + if (includeHeaderNodes) { + addHeaderNodes(m_rootProjectNode.get(), m_knownHeaders, allFiles); + } + addFileSystemNodes(m_rootProjectNode.get(), allFiles); return std::move(m_rootProjectNode); } @@ -230,19 +233,23 @@ void FileApiReader::endState(const QFileInfo &replyFi) const FilePath sourceDirectory = m_parameters.sourceDirectory; const FilePath buildDirectory = m_parameters.workDirectory; + const FilePath topCmakeFile = m_cmakeFiles.size() == 1 ? *m_cmakeFiles.begin() : FilePath{}; m_lastReplyTimestamp = replyFi.lastModified(); m_future = runAsync(ProjectExplorerPlugin::sharedThreadPool(), - [replyFi, sourceDirectory, buildDirectory]() { + [replyFi, sourceDirectory, buildDirectory, topCmakeFile]() { auto result = std::make_unique(); - FileApiData data = FileApiParser::parseData(replyFi, - result->errorMessage); + FileApiData data = FileApiParser::parseData(replyFi, result->errorMessage); if (!result->errorMessage.isEmpty()) { qWarning() << result->errorMessage; - return result.release(); + *result = generateFallbackData(topCmakeFile, + sourceDirectory, + buildDirectory, + result->errorMessage); + } else { + *result = extractData(data, sourceDirectory, buildDirectory); } - *result = extractData(data, sourceDirectory, buildDirectory); if (!result->errorMessage.isEmpty()) { qWarning() << result->errorMessage; } diff --git a/src/plugins/cmakeprojectmanager/fileapireader.h b/src/plugins/cmakeprojectmanager/fileapireader.h index 0b578511ecb..d8dc9eb0c0c 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.h +++ b/src/plugins/cmakeprojectmanager/fileapireader.h @@ -67,7 +67,9 @@ public: QList takeBuildTargets(QString &errorMessage); CMakeConfig takeParsedConfiguration(QString &errorMessage); std::unique_ptr generateProjectTree( - const QList &allFiles, QString &errorMessage); + const QList &allFiles, + QString &errorMessage, + bool includeHeaderNodes); ProjectExplorer::RawProjectParts createRawProjectParts(QString &errorMessage); signals: diff --git a/src/plugins/cmakeprojectmanager/projecttreehelper.cpp b/src/plugins/cmakeprojectmanager/projecttreehelper.cpp index 8a930de35b1..a97856fe89f 100644 --- a/src/plugins/cmakeprojectmanager/projecttreehelper.cpp +++ b/src/plugins/cmakeprojectmanager/projecttreehelper.cpp @@ -208,5 +208,31 @@ void addHeaderNodes(ProjectNode *root, root->addNode(std::move(headerNode)); } +void addFileSystemNodes(ProjectNode *root, const QList &allFiles) +{ + QTC_ASSERT(root, return ); + + static QIcon fileSystemNodeIcon = Core::FileIconProvider::directoryIcon( + ProjectExplorer::Constants::FILEOVERLAY_UNKNOWN); + auto fileSystemNode = std::make_unique(root->filePath()); + fileSystemNode->setPriority(Node::DefaultPriority - 6); + fileSystemNode->setDisplayName( + QCoreApplication::translate("CMakeProjectManager::Internal::ProjectTreeHelper", + "")); + fileSystemNode->setIcon(fileSystemNodeIcon); + + for (const FileNode *fn : allFiles) { + if (!fn->filePath().isChildOf(root->filePath())) + continue; + + std::unique_ptr node(fn->clone()); + node->setEnabled(false); + fileSystemNode->addNestedNode(std::move(node)); + } + + if (!fileSystemNode->isEmpty()) + root->addNode(std::move(fileSystemNode)); +} + } // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/projecttreehelper.h b/src/plugins/cmakeprojectmanager/projecttreehelper.h index a591cabf0e1..eabb4a0096b 100644 --- a/src/plugins/cmakeprojectmanager/projecttreehelper.h +++ b/src/plugins/cmakeprojectmanager/projecttreehelper.h @@ -68,5 +68,7 @@ void addHeaderNodes(ProjectExplorer::ProjectNode *root, QSet &seenHeaders, const QList &allFiles); +void addFileSystemNodes(ProjectExplorer::ProjectNode *root, + const QList &allFiles); } // namespace Internal } // namespace CMakeProjectManager