diff --git a/src/plugins/clangcodemodel/pchmanager.cpp b/src/plugins/clangcodemodel/pchmanager.cpp index dd81ebf94b6a8ddde5d3a46917cfa4e9bf37e4f6..295cf4fc4e9fee3f86d8af84ce14a75971035179 100644 --- a/src/plugins/clangcodemodel/pchmanager.cpp +++ b/src/plugins/clangcodemodel/pchmanager.cpp @@ -34,6 +34,7 @@ #include <coreplugin/icore.h> #include <coreplugin/progressmanager/progressmanager.h> +#include <utils/qtcassert.h> #include <utils/runextensions.h> #include <QFile> @@ -153,14 +154,36 @@ void PchManager::updatePchInfo(ClangProjectSettings *cps, const QList<ProjectPart::Ptr> &projectParts) { if (m_pchGenerationWatcher.isRunning()) { -// m_pchGenerationWatcher.cancel(); m_pchGenerationWatcher.waitForFinished(); } - QFuture<void> future = QtConcurrent::run(&PchManager::doPchInfoUpdate, - cps->pchUsage(), - cps->customPchFile(), - projectParts); + const QString customPchFile = cps->customPchFile(); + const ClangProjectSettings::PchUsage pchUsage = cps->pchUsage(); + + void (*updateFunction)(QFutureInterface<void> &future, + const PchManager::UpdateParams ¶ms) = 0; + QString message; + if (pchUsage == ClangProjectSettings::PchUse_None + || (pchUsage == ClangProjectSettings::PchUse_Custom && customPchFile.isEmpty())) { + updateFunction = &PchManager::doPchInfoUpdateNone; + message = QLatin1String("updatePchInfo: switching to none"); + } else if (pchUsage == ClangProjectSettings::PchUse_BuildSystem_Fuzzy) { + updateFunction = &PchManager::doPchInfoUpdateFuzzy; + message = QLatin1String("updatePchInfo: switching to build system (fuzzy)"); + } else if (pchUsage == ClangProjectSettings::PchUse_BuildSystem_Exact) { + updateFunction = &PchManager::doPchInfoUpdateExact; + message = QLatin1String("updatePchInfo: switching to build system (exact)"); + } else if (pchUsage == ClangProjectSettings::PchUse_Custom) { + updateFunction = &PchManager::doPchInfoUpdateCustom; + message = QLatin1String("updatePchInfo: switching to custom") + customPchFile; + } + + QTC_ASSERT(updateFunction && !message.isEmpty(), return); + + Core::MessageManager::write(message, Core::MessageManager::Silent); + const UpdateParams updateParams = UpdateParams(customPchFile, projectParts); + QFuture<void> future + = QtConcurrent::run<void, const UpdateParams &>(updateFunction, updateParams); m_pchGenerationWatcher.setFuture(future); Core::ProgressManager::addTask(future, tr("Precompiling..."), "Key.Tmp.Precompiling"); } @@ -214,183 +237,177 @@ CppTools::ProjectFile::Kind getPrefixFileKind(bool hasObjectiveC, bool hasCPlusP } -void PchManager::doPchInfoUpdate(QFutureInterface<void> &future, - ClangProjectSettings::PchUsage pchUsage, - const QString customPchFile, - const QList<ProjectPart::Ptr> projectParts) +void PchManager::doPchInfoUpdateNone(QFutureInterface<void> &future, const PchManager::UpdateParams ¶ms) { - PchManager *pchManager = PchManager::instance(); + future.setProgressRange(0, 1); + PchInfo::Ptr emptyPch = PchInfo::createEmpty(); + PchManager::instance()->setPCHInfo(params.projectParts, emptyPch, + qMakePair(true, QStringList())); + future.setProgressValue(1); +} -// qDebug() << "switching to" << pchUsage; +void PchManager::doPchInfoUpdateFuzzy(QFutureInterface<void> &future, const PchManager::UpdateParams ¶ms) +{ + QHash<QString, QSet<QString> > includes, frameworks; + QHash<QString, QSet<QByteArray> > definesPerPCH; + QHash<QString, bool> objc; + QHash<QString, bool> cplusplus; + QHash<QString, ProjectPart::QtVersion> qtVersions; + QHash<QString, ProjectPart::CVersion> cVersions; + QHash<QString, ProjectPart::CXXVersion> cxxVersions; + QHash<QString, ProjectPart::CXXExtensions> cxxExtensionsMap; + QHash<QString, QList<ProjectPart::Ptr> > inputToParts; + foreach (const ProjectPart::Ptr &projectPart, params.projectParts) { + if (projectPart->precompiledHeaders.isEmpty()) + continue; + const QString &pch = projectPart->precompiledHeaders.first(); // TODO: support more than 1 PCH file. + if (!QFile(pch).exists()) + continue; + inputToParts[pch].append(projectPart); + + includes[pch].unite(QSet<QString>::fromList(projectPart->includePaths)); + frameworks[pch].unite(QSet<QString>::fromList(projectPart->frameworkPaths)); + cVersions[pch] = std::max(cVersions.value(pch, ProjectPart::C89), projectPart->cVersion); + cxxVersions[pch] = std::max(cxxVersions.value(pch, ProjectPart::CXX98), projectPart->cxxVersion); + cxxExtensionsMap[pch] = cxxExtensionsMap[pch] | projectPart->cxxExtensions; + + if (hasObjCFiles(projectPart)) + objc[pch] = true; + if (hasCppFiles(projectPart)) + cplusplus[pch] = true; + + QSet<QByteArray> projectDefines = QSet<QByteArray>::fromList(projectPart->toolchainDefines.split('\n')); + QMutableSetIterator<QByteArray> iter(projectDefines); + while (iter.hasNext()){ + QByteArray v = iter.next(); + if (v.startsWith("#define _") || v.isEmpty()) // TODO: see ProjectPart::createClangOptions + iter.remove(); + } + projectDefines.unite(QSet<QByteArray>::fromList(projectPart->projectDefines.split('\n'))); - if (pchUsage == ClangProjectSettings::PchUse_None - || (pchUsage == ClangProjectSettings::PchUse_Custom && customPchFile.isEmpty())) { - future.setProgressRange(0, 2); - Core::MessageManager::write(QLatin1String("updatePchInfo: switching to none"), - Core::MessageManager::Silent); - PchInfo::Ptr emptyPch = PchInfo::createEmpty(); - pchManager->setPCHInfo(projectParts, emptyPch, qMakePair(true, QStringList())); - future.setProgressValue(1); - } else if (pchUsage == ClangProjectSettings::PchUse_BuildSystem_Fuzzy) { - Core::MessageManager::write( - QLatin1String("updatePchInfo: switching to build system (fuzzy)"), - Core::MessageManager::Silent); - QHash<QString, QSet<QString> > includes, frameworks; - QHash<QString, QSet<QByteArray> > definesPerPCH; - QHash<QString, bool> objc; - QHash<QString, bool> cplusplus; - QHash<QString, ProjectPart::QtVersion> qtVersions; - QHash<QString, ProjectPart::CVersion> cVersions; - QHash<QString, ProjectPart::CXXVersion> cxxVersions; - QHash<QString, ProjectPart::CXXExtensions> cxxExtensionsMap; - QHash<QString, QList<ProjectPart::Ptr> > inputToParts; - foreach (const ProjectPart::Ptr &projectPart, projectParts) { - if (projectPart->precompiledHeaders.isEmpty()) - continue; - const QString &pch = projectPart->precompiledHeaders.first(); // TODO: support more than 1 PCH file. - if (!QFile(pch).exists()) - continue; - inputToParts[pch].append(projectPart); - - includes[pch].unite(QSet<QString>::fromList(projectPart->includePaths)); - frameworks[pch].unite(QSet<QString>::fromList(projectPart->frameworkPaths)); - cVersions[pch] = std::max(cVersions.value(pch, ProjectPart::C89), projectPart->cVersion); - cxxVersions[pch] = std::max(cxxVersions.value(pch, ProjectPart::CXX98), projectPart->cxxVersion); - cxxExtensionsMap[pch] = cxxExtensionsMap[pch] | projectPart->cxxExtensions; - - if (hasObjCFiles(projectPart)) - objc[pch] = true; - if (hasCppFiles(projectPart)) - cplusplus[pch] = true; - - QSet<QByteArray> projectDefines = QSet<QByteArray>::fromList(projectPart->toolchainDefines.split('\n')); - QMutableSetIterator<QByteArray> iter(projectDefines); - while (iter.hasNext()){ - QByteArray v = iter.next(); - if (v.startsWith("#define _") || v.isEmpty()) // TODO: see ProjectPart::createClangOptions - iter.remove(); - } - projectDefines.unite(QSet<QByteArray>::fromList(projectPart->projectDefines.split('\n'))); + if (definesPerPCH.contains(pch)) { + definesPerPCH[pch].intersect(projectDefines); + } else { + definesPerPCH[pch] = projectDefines; + } - if (definesPerPCH.contains(pch)) { - definesPerPCH[pch].intersect(projectDefines); - } else { - definesPerPCH[pch] = projectDefines; - } + qtVersions[pch] = projectPart->qtVersion; + } - qtVersions[pch] = projectPart->qtVersion; - } + future.setProgressRange(0, definesPerPCH.size() + 1); + future.setProgressValue(0); - future.setProgressRange(0, definesPerPCH.size() + 1); - future.setProgressValue(0); - - foreach (const QString &pch, inputToParts.keys()) { - if (future.isCanceled()) - return; - ProjectPart::Ptr projectPart(new ProjectPart); - projectPart->qtVersion = qtVersions[pch]; - projectPart->cVersion = cVersions[pch]; - projectPart->cxxVersion = cxxVersions[pch]; - projectPart->cxxExtensions = cxxExtensionsMap[pch]; - projectPart->includePaths = includes[pch].toList(); - projectPart->frameworkPaths = frameworks[pch].toList(); - - QList<QByteArray> defines = definesPerPCH[pch].toList(); - if (!defines.isEmpty()) { - projectPart->projectDefines = defines[0]; - for (int i = 1; i < defines.size(); ++i) { - projectPart->projectDefines += '\n'; - projectPart->projectDefines += defines[i]; - } + foreach (const QString &pch, inputToParts.keys()) { + if (future.isCanceled()) + return; + ProjectPart::Ptr projectPart(new ProjectPart); + projectPart->qtVersion = qtVersions[pch]; + projectPart->cVersion = cVersions[pch]; + projectPart->cxxVersion = cxxVersions[pch]; + projectPart->cxxExtensions = cxxExtensionsMap[pch]; + projectPart->includePaths = includes[pch].toList(); + projectPart->frameworkPaths = frameworks[pch].toList(); + + QList<QByteArray> defines = definesPerPCH[pch].toList(); + if (!defines.isEmpty()) { + projectPart->projectDefines = defines[0]; + for (int i = 1; i < defines.size(); ++i) { + projectPart->projectDefines += '\n'; + projectPart->projectDefines += defines[i]; } + } - CppTools::ProjectFile::Kind prefixFileKind = - getPrefixFileKind(objc.value(pch, false), cplusplus.value(pch, false)); + CppTools::ProjectFile::Kind prefixFileKind = + getPrefixFileKind(objc.value(pch, false), cplusplus.value(pch, false)); - QStringList options = Utils::createClangOptions(projectPart, prefixFileKind); - projectPart.reset(); + QStringList options = Utils::createClangOptions(projectPart, prefixFileKind); + projectPart.reset(); - PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, true); - QPair<bool, QStringList> msgs = qMakePair(true, QStringList()); - if (pchInfo.isNull()) { + PchManager *pchManager = PchManager::instance(); + PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, true); + QPair<bool, QStringList> msgs = qMakePair(true, QStringList()); + if (pchInfo.isNull()) { - pchInfo = PchInfo::createWithFileName(pch, options, objc[pch]); - msgs = precompile(pchInfo); - } - pchManager->setPCHInfo(inputToParts[pch], pchInfo, msgs); - future.setProgressValue(future.progressValue() + 1); + pchInfo = PchInfo::createWithFileName(pch, options, objc[pch]); + msgs = precompile(pchInfo); } - } else if (pchUsage == ClangProjectSettings::PchUse_BuildSystem_Exact) { - future.setProgressRange(0, projectParts.size() + 1); - future.setProgressValue(0); - Core::MessageManager::write( - QLatin1String("updatePchInfo: switching to build system (exact)"), - Core::MessageManager::Silent); - foreach (const ProjectPart::Ptr &projectPart, projectParts) { - if (future.isCanceled()) - return; - if (projectPart->precompiledHeaders.isEmpty()) - continue; - const QString &pch = projectPart->precompiledHeaders.first(); // TODO: support more than 1 PCH file. - if (!QFile(pch).exists()) - continue; + pchManager->setPCHInfo(inputToParts[pch], pchInfo, msgs); + future.setProgressValue(future.progressValue() + 1); + } - const bool hasObjC = hasObjCFiles(projectPart); - QStringList options = Utils::createClangOptions( - projectPart, getPrefixFileKind(hasObjC, hasCppFiles(projectPart))); + future.setProgressValue(future.progressValue() + 1); +} - PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, false); - QPair<bool, QStringList> msgs = qMakePair(true, QStringList()); - if (pchInfo.isNull()) { - pchInfo = PchInfo::createWithFileName(pch, options, hasObjC); - msgs = precompile(pchInfo); - } - pchManager->setPCHInfo(QList<ProjectPart::Ptr>() << projectPart, - pchInfo, msgs); - future.setProgressValue(future.progressValue() + 1); - } - } else if (pchUsage == ClangProjectSettings::PchUse_Custom) { - future.setProgressRange(0, 2); - future.setProgressValue(0); - Core::MessageManager::write( - QLatin1String("updatePchInfo: switching to custom") + customPchFile, - Core::MessageManager::Silent); - - QSet<QString> includes, frameworks; - bool objc = false; - bool cplusplus = false; - ProjectPart::Ptr united(new ProjectPart()); - united->cxxVersion = ProjectPart::CXX98; - foreach (const ProjectPart::Ptr &projectPart, projectParts) { - includes.unite(QSet<QString>::fromList(projectPart->includePaths)); - frameworks.unite(QSet<QString>::fromList(projectPart->frameworkPaths)); - united->cVersion = std::max(united->cVersion, projectPart->cVersion); - united->cxxVersion = std::max(united->cxxVersion, projectPart->cxxVersion); - united->qtVersion = std::max(united->qtVersion, projectPart->qtVersion); - objc |= hasObjCFiles(projectPart); - cplusplus |= hasCppFiles(projectPart); - } - united->frameworkPaths = frameworks.toList(); - united->includePaths = includes.toList(); - QStringList opts = Utils::createClangOptions( - united, getPrefixFileKind(objc, cplusplus)); - united.clear(); - - PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(customPchFile, opts, true); - QPair<bool, QStringList> msgs = qMakePair(true, QStringList());; +void PchManager::doPchInfoUpdateExact(QFutureInterface<void> &future, const PchManager::UpdateParams ¶ms) +{ + future.setProgressRange(0, params.projectParts.size() + 1); + future.setProgressValue(0); + foreach (const ProjectPart::Ptr &projectPart, params.projectParts) { if (future.isCanceled()) return; + if (projectPart->precompiledHeaders.isEmpty()) + continue; + const QString &pch = projectPart->precompiledHeaders.first(); // TODO: support more than 1 PCH file. + if (!QFile(pch).exists()) + continue; + + const bool hasObjC = hasObjCFiles(projectPart); + QStringList options = Utils::createClangOptions( + projectPart, getPrefixFileKind(hasObjC, hasCppFiles(projectPart))); + + PchManager *pchManager = PchManager::instance(); + PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, false); + QPair<bool, QStringList> msgs = qMakePair(true, QStringList()); if (pchInfo.isNull()) { - pchInfo = PchInfo::createWithFileName(customPchFile, opts, objc); + pchInfo = PchInfo::createWithFileName(pch, options, hasObjC); msgs = precompile(pchInfo); } - pchManager->setPCHInfo(projectParts, pchInfo, msgs); - future.setProgressValue(1); + pchManager->setPCHInfo(QList<ProjectPart::Ptr>() << projectPart, + pchInfo, msgs); + future.setProgressValue(future.progressValue() + 1); } future.setProgressValue(future.progressValue() + 1); } +void PchManager::doPchInfoUpdateCustom(QFutureInterface<void> &future, const PchManager::UpdateParams ¶ms) +{ + future.setProgressRange(0, 1); + future.setProgressValue(0); + + QSet<QString> includes, frameworks; + bool objc = false; + bool cplusplus = false; + ProjectPart::Ptr united(new ProjectPart()); + united->cxxVersion = ProjectPart::CXX98; + foreach (const ProjectPart::Ptr &projectPart, params.projectParts) { + includes.unite(QSet<QString>::fromList(projectPart->includePaths)); + frameworks.unite(QSet<QString>::fromList(projectPart->frameworkPaths)); + united->cVersion = std::max(united->cVersion, projectPart->cVersion); + united->cxxVersion = std::max(united->cxxVersion, projectPart->cxxVersion); + united->qtVersion = std::max(united->qtVersion, projectPart->qtVersion); + objc |= hasObjCFiles(projectPart); + cplusplus |= hasCppFiles(projectPart); + } + united->frameworkPaths = frameworks.toList(); + united->includePaths = includes.toList(); + QStringList opts = Utils::createClangOptions( + united, getPrefixFileKind(objc, cplusplus)); + united.clear(); + + PchManager *pchManager = PchManager::instance(); + PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(params.customPchFile, opts, true); + QPair<bool, QStringList> msgs = qMakePair(true, QStringList());; + if (future.isCanceled()) + return; + if (pchInfo.isNull()) { + pchInfo = PchInfo::createWithFileName(params.customPchFile, opts, objc); + msgs = precompile(pchInfo); + } + pchManager->setPCHInfo(params.projectParts, pchInfo, msgs); + future.setProgressValue(1); +} + PchInfo::Ptr PchManager::findMatchingPCH(const QString &inputFileName, const QStringList &options, bool fuzzyMatching) const diff --git a/src/plugins/clangcodemodel/pchmanager.h b/src/plugins/clangcodemodel/pchmanager.h index 2c79554dc0e61d01ba9866cf45eeab6d18dcf11b..263258f91654e8b98e8dd14791b7a8da8c3c509b 100644 --- a/src/plugins/clangcodemodel/pchmanager.h +++ b/src/plugins/clangcodemodel/pchmanager.h @@ -75,12 +75,21 @@ private slots: void updateActivePchFiles(); private: + struct UpdateParams { + UpdateParams(const QString &customPchFile, const QList<ProjectPart::Ptr> &projectParts) + : customPchFile(customPchFile) , projectParts(projectParts) {} + const QString customPchFile; + const QList<ProjectPart::Ptr> projectParts; + }; + void updatePchInfo(ClangProjectSettings *cps, const QList<ProjectPart::Ptr> &projectParts); - static void doPchInfoUpdate(QFutureInterface<void> &future, - ClangProjectSettings::PchUsage pchUsage, - const QString customPchFile, - const QList<ProjectPart::Ptr> projectParts); + + static void doPchInfoUpdateNone(QFutureInterface<void> &future, const UpdateParams ¶ms); + static void doPchInfoUpdateFuzzy(QFutureInterface<void> &future, const UpdateParams ¶ms); + static void doPchInfoUpdateExact(QFutureInterface<void> &future, const UpdateParams ¶ms); + static void doPchInfoUpdateCustom(QFutureInterface<void> &future, const UpdateParams ¶ms); + void setPCHInfo(const QList<ProjectPart::Ptr> &projectParts, const PchInfo::Ptr &pchInfo, const QPair<bool, QStringList> &msgs);