diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index 2575f7bdc478c1d47b5b0b4dbce4e05e6b5b84b7..5c5314b31d2e5af554e3b3f923e240fd7d048c17 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -380,13 +380,15 @@ void BuildDirManager::clearCache() QList<CMakeBuildTarget> BuildDirManager::buildTargets() const { - QTC_ASSERT(m_reader, return QList<CMakeBuildTarget>()); + if (!m_reader) + return QList<CMakeBuildTarget>(); return m_reader->buildTargets(); } CMakeConfig BuildDirManager::parsedConfiguration() const { - QTC_ASSERT(m_reader, return m_cmakeCache); + if (!m_reader) + return m_cmakeCache; if (m_cmakeCache.isEmpty()) m_cmakeCache = m_reader->parsedConfiguration(); return m_cmakeCache; diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.cpp b/src/plugins/cmakeprojectmanager/tealeafreader.cpp index 37d9b4917694778e90cb1d1a579ee4a5414a8bbe..8a6fefda01fbff16c839993a6df5356d1d886597 100644 --- a/src/plugins/cmakeprojectmanager/tealeafreader.cpp +++ b/src/plugins/cmakeprojectmanager/tealeafreader.cpp @@ -320,10 +320,9 @@ CMakeConfig TeaLeafReader::parseConfiguration(const FileName &cacheFile, QString void TeaLeafReader::generateProjectTree(CMakeProjectNode *root, const QList<FileNode *> &allFiles) { - Q_UNUSED(allFiles); root->setDisplayName(m_projectName); - // Delete no longer necessary file watcher: + // Delete no longer necessary file watcher based on m_cmakeFiles: const QSet<FileName> currentWatched = transform(m_watchedFiles, [](CMakeFile *cmf) { return cmf->filePath(); }); const QSet<FileName> toWatch = m_cmakeFiles; @@ -346,8 +345,59 @@ void TeaLeafReader::generateProjectTree(CMakeProjectNode *root, const QList<File m_watchedFiles.insert(cm); } - QList<FileNode *> fileNodes = m_files; - root->buildTree(fileNodes); + QList<FileNode *> added; + QList<FileNode *> deleted; + + ProjectExplorer::compareSortedLists(m_files, allFiles, deleted, added, Node::sortByPath); + + QSet<FileName> allIncludePathSet; + for (const CMakeBuildTarget &bt : m_buildTargets) { + const QList<Utils::FileName> targetIncludePaths + = Utils::filtered(bt.includeFiles, [root](const Utils::FileName &fn) { + return fn.isChildOf(root->filePath()); + }); + allIncludePathSet.unite(QSet<FileName>::fromList(targetIncludePaths)); + } + const QList<FileName> allIncludePaths = allIncludePathSet.toList(); + + QList<FileNode *> includedHeaderFiles; + QList<FileNode *> unusedFileNodes; + std::tie(includedHeaderFiles, unusedFileNodes) + = Utils::partition(allFiles, [&allIncludePaths](const FileNode *fn) -> bool { + if (fn->fileType() != FileType::Header) + return false; + + for (const FileName &inc : allIncludePaths) { + if (fn->filePath().isChildOf(inc)) + return true; + } + return false; + }); + + const auto knownFiles = QSet<FileName>::fromList(Utils::transform(m_files, [](const FileNode *fn) { return fn->filePath(); })); + QList<FileNode *> uniqueHeaders; + foreach (FileNode *ifn, includedHeaderFiles) { + if (!knownFiles.contains(ifn->filePath())) { + uniqueHeaders.append(ifn); + ifn->setEnabled(false); + } + } + + QList<FileNode *> fileNodes = m_files + uniqueHeaders; + + // Filter out duplicate nodes that e.g. the servermode reader introduces: + QSet<FileName> uniqueFileNames; + QSet<Node *> uniqueNodes; + foreach (FileNode *fn, root->recursiveFileNodes()) { + const int count = uniqueFileNames.count(); + uniqueFileNames.insert(fn->filePath()); + if (count != uniqueFileNames.count()) + uniqueNodes.insert(static_cast<Node *>(fn)); + } + root->trim(uniqueNodes); + root->removeProjectNodes(root->projectNodes()); // Remove all project nodes + + root->buildTree(fileNodes, m_parameters.sourceDirectory); m_files.clear(); // Some of the FileNodes in files() were deleted! }