diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp index 75d82c2e65f..eb83136e68d 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp +++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include @@ -70,7 +70,8 @@ using namespace AutotoolsProjectManager::Internal; using namespace ProjectExplorer; AutotoolsProject::AutotoolsProject(AutotoolsManager *manager, const QString &fileName) : - m_fileWatcher(new Utils::FileSystemWatcher(this)) + m_fileWatcher(new Utils::FileSystemWatcher(this)), + m_cppCodeModelUpdater(new CppTools::CppProjectUpdater(this)) { setId(Constants::AUTOTOOLS_PROJECT_ID); setProjectManager(manager); @@ -86,6 +87,8 @@ AutotoolsProject::AutotoolsProject(AutotoolsManager *manager, const QString &fil AutotoolsProject::~AutotoolsProject() { + delete m_cppCodeModelUpdater; + setRootProjectNode(0); if (m_makefileParserThread != 0) { @@ -270,42 +273,47 @@ static QStringList filterIncludes(const QString &absSrc, const QString &absBuild void AutotoolsProject::updateCppCodeModel() { - CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); + const Kit *k = nullptr; + if (Target *target = activeTarget()) + k = target->kit(); + else + k = KitManager::defaultKit(); + QTC_ASSERT(k, return); - m_codeModelFuture.cancel(); - CppTools::ProjectInfo pInfo(this); - CppTools::ProjectPartBuilder ppBuilder(pInfo); + ToolChain *cToolChain + = ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::C_LANGUAGE_ID); + ToolChain *cxxToolChain + = ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID); - ppBuilder.setProjectFile(projectFilePath().toString()); + m_cppCodeModelUpdater->cancel(); + + CppTools::RawProjectPart rpp; + rpp.setProjectFile(projectFilePath().toString()); CppTools::ProjectPart::QtVersion activeQtVersion = CppTools::ProjectPart::NoQt; - if (QtSupport::BaseQtVersion *qtVersion = - QtSupport::QtKitInformation::qtVersion(activeTarget()->kit())) { + if (QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(k)) { if (qtVersion->qtVersion() < QtSupport::QtVersionNumber(5,0,0)) activeQtVersion = CppTools::ProjectPart::Qt4; else activeQtVersion = CppTools::ProjectPart::Qt5; } - ppBuilder.setQtVersion(activeQtVersion); + rpp.setQtVersion(activeQtVersion); const QStringList cflags = m_makefileParserThread->cflags(); QStringList cxxflags = m_makefileParserThread->cxxflags(); if (cxxflags.isEmpty()) cxxflags = cflags; - ppBuilder.setCFlags(cflags); - ppBuilder.setCxxFlags(cxxflags); + rpp.setFlagsForC({cToolChain, cflags}); + rpp.setFlagsForCxx({cxxToolChain, cxxflags}); const QString absSrc = projectDirectory().toString(); const Target *target = activeTarget(); const QString absBuild = (target && target->activeBuildConfiguration()) ? target->activeBuildConfiguration()->buildDirectory().toString() : QString(); - ppBuilder.setIncludePaths(filterIncludes(absSrc, absBuild, m_makefileParserThread->includePaths())); - ppBuilder.setDefines(m_makefileParserThread->defines()); + rpp.setIncludePaths(filterIncludes(absSrc, absBuild, m_makefileParserThread->includePaths())); + rpp.setDefines(m_makefileParserThread->defines()); + rpp.setFiles(m_files); - const QList languages = ppBuilder.createProjectPartsForFiles(m_files); - foreach (Core::Id language, languages) - setProjectLanguage(language, true); - - m_codeModelFuture = modelManager->updateProjectInfo(pInfo); + m_cppCodeModelUpdater->update({this, cToolChain, cxxToolChain, k, {rpp}}); } diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.h b/src/plugins/autotoolsprojectmanager/autotoolsproject.h index d98686a81f0..7ee1017ae38 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsproject.h +++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.h @@ -37,6 +37,8 @@ QT_FORWARD_DECLARE_CLASS(QDir) namespace Utils { class FileSystemWatcher; } +namespace CppTools { class CppProjectUpdater; } + namespace ProjectExplorer { class Node; class FolderNode; @@ -119,7 +121,7 @@ private: /// Responsible for parsing the makefiles asynchronously in a thread MakefileParserThread *m_makefileParserThread = nullptr; - QFuture m_codeModelFuture; + CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr; }; } // namespace Internal diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index bbeb34deed2..9b57ce0ab59 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -289,10 +288,10 @@ void BuildDirManager::generateProjectTree(CMakeListsNode *root, const QListaddNode(new FileNode(projectFile, FileType::Project, false)); } -QSet BuildDirManager::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) +void BuildDirManager::updateCodeModel(CppTools::RawProjectParts &rpps) { - QTC_ASSERT(m_reader, return QSet()); - return m_reader->updateCodeModel(ppBuilder); + QTC_ASSERT(m_reader, return); + return m_reader->updateCodeModel(rpps); } void BuildDirManager::parse() diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.h b/src/plugins/cmakeprojectmanager/builddirmanager.h index 0bfac24365c..85b95884648 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.h +++ b/src/plugins/cmakeprojectmanager/builddirmanager.h @@ -37,8 +37,6 @@ #include #include -namespace CppTools { class ProjectPartBuilder; } - namespace ProjectExplorer { class FileNode; class IOutputParser; @@ -73,7 +71,7 @@ public: void generateProjectTree(CMakeListsNode *root, const QList &allFiles); - QSet updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder); + void updateCodeModel(CppTools::RawProjectParts &rpps); QList buildTargets() const; CMakeConfig parsedConfiguration() const; diff --git a/src/plugins/cmakeprojectmanager/builddirreader.h b/src/plugins/cmakeprojectmanager/builddirreader.h index f28c974ecca..b13de736f20 100644 --- a/src/plugins/cmakeprojectmanager/builddirreader.h +++ b/src/plugins/cmakeprojectmanager/builddirreader.h @@ -29,6 +29,8 @@ #include "cmakeproject.h" #include "cmaketool.h" +#include + #include #include #include @@ -36,8 +38,6 @@ #include #include -namespace CppTools { class ProjectPartBuilder; } - namespace CMakeProjectManager { namespace Internal { @@ -97,7 +97,7 @@ public: virtual QList buildTargets() const = 0; virtual void generateProjectTree(CMakeListsNode *root, const QList &allFiles) = 0; - virtual QSet updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) = 0; + virtual void updateCodeModel(CppTools::RawProjectParts &rpps) = 0; signals: void isReadyNow() const; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 10468ac7900..960bb9c59a8 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -220,9 +220,9 @@ void CMakeBuildConfiguration::generateProjectTree(CMakeListsNode *root, m_buildDirManager->generateProjectTree(root, allFiles); } -QSet CMakeBuildConfiguration::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) +void CMakeBuildConfiguration::updateCodeModel(CppTools::RawProjectParts &rpps) { - return m_buildDirManager->updateCodeModel(ppBuilder); + m_buildDirManager->updateCodeModel(rpps); } FileName CMakeBuildConfiguration::shadowBuildDirectory(const FileName &projectFilePath, diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h index ce561412b1c..1afd9c33d7b 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h @@ -29,12 +29,13 @@ #include "cmakeproject.h" #include "configmodel.h" +#include + #include #include #include -namespace CppTools { class ProjectPartBuilder; } namespace ProjectExplorer { class ToolChain; } namespace CMakeProjectManager { @@ -86,7 +87,7 @@ public: QList buildTargets() const; void generateProjectTree(CMakeListsNode *root, const QList &allFiles) const; - QSet updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder); + void updateCodeModel(CppTools::RawProjectParts &rpps); static Utils::FileName shadowBuildDirectory(const Utils::FileName &projectFilePath, const ProjectExplorer::Kit *k, diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 6d022141eaf..d89e4e86a02 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -33,11 +33,11 @@ #include "cmakeprojectmanager.h" #include -#include +#include +#include #include #include #include -#include #include #include #include @@ -74,6 +74,7 @@ using namespace Internal; \class CMakeProject */ CMakeProject::CMakeProject(CMakeManager *manager, const FileName &fileName) + : m_cppCodeModelUpdater(new CppTools::CppProjectUpdater(this)) { setId(CMakeProjectManager::Constants::CMAKEPROJECT_ID); setProjectManager(manager); @@ -133,8 +134,8 @@ CMakeProject::~CMakeProject() future.cancel(); future.waitForFinished(); } + delete m_cppCodeModelUpdater; setRootProjectNode(nullptr); - m_codeModelFuture.cancel(); qDeleteAll(m_extraCompilers); qDeleteAll(m_allFiles); } @@ -165,10 +166,6 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc) return; } - CppTools::CppModelManager *modelmanager = CppTools::CppModelManager::instance(); - CppTools::ProjectInfo pinfo(this); - CppTools::ProjectPartBuilder ppBuilder(pinfo); - CppTools::ProjectPart::QtVersion activeQtVersion = CppTools::ProjectPart::NoQt; if (QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(k)) { if (qtVersion->qtVersion() < QtSupport::QtVersionNumber(5,0,0)) @@ -177,14 +174,17 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc) activeQtVersion = CppTools::ProjectPart::Qt5; } - ppBuilder.setQtVersion(activeQtVersion); + CppTools::RawProjectParts rpps; + bc->updateCodeModel(rpps); - const QSet languages = bc->updateCodeModel(ppBuilder); - for (const auto &lid : languages) - setProjectLanguage(lid, true); + for (CppTools::RawProjectPart &rpp : rpps) { + // TODO: Set the Qt version only if target actually depends on Qt. + rpp.setQtVersion(activeQtVersion); + // TODO: Support also C + rpp.setFlagsForCxx({tc, rpp.flagsForCxx.commandLineFlags}); + } - m_codeModelFuture.cancel(); - m_codeModelFuture = modelmanager->updateProjectInfo(pinfo); + m_cppCodeModelUpdater->update({this, nullptr, tc, k, rpps}); updateQmlJSCodeModel(); diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h index 959aea47d30..7d8711c9f19 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.h +++ b/src/plugins/cmakeprojectmanager/cmakeproject.h @@ -43,6 +43,8 @@ QT_BEGIN_NAMESPACE class QFileSystemWatcher; QT_END_NAMESPACE +namespace CppTools { class CppProjectUpdater; } + namespace CMakeProjectManager { namespace Internal { @@ -134,7 +136,7 @@ private: // TODO probably need a CMake specific node structure QList m_buildTargets; - QFuture m_codeModelFuture; + CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr; QList m_extraCompilers; Internal::TreeScanner m_treeScanner; diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp index 23db99ff31d..c177e303b79 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.cpp +++ b/src/plugins/cmakeprojectmanager/servermodereader.cpp @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -287,9 +286,8 @@ void ServerModeReader::generateProjectTree(CMakeListsNode *root, addProjects(root, m_projects, allFiles); } -QSet ServerModeReader::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) +void ServerModeReader::updateCodeModel(CppTools::RawProjectParts &rpps) { - QSet languages; int counter = 0; foreach (const FileGroup *fg, m_fileGroups) { ++counter; @@ -304,23 +302,29 @@ QSet ServerModeReader::updateCodeModel(CppTools::ProjectPartBuilder &p const QStringList flags = QtcProcess::splitArgs(fg->compileFlags); const QStringList includes = transform(fg->includePaths, [](const IncludePath *ip) { return ip->path.toString(); }); - ppBuilder.setProjectFile(fg->target->sourceDirectory.toString() + "/CMakeLists.txt"); - ppBuilder.setDisplayName(fg->target->name + QString::number(counter)); - ppBuilder.setDefines(defineArg.toUtf8()); - ppBuilder.setIncludePaths(includes); - ppBuilder.setCFlags(flags); - ppBuilder.setCxxFlags(flags); + CppTools::RawProjectPart rpp; + rpp.setProjectFile(fg->target->sourceDirectory.toString() + "/CMakeLists.txt"); + rpp.setDisplayName(fg->target->name + QString::number(counter)); + rpp.setDefines(defineArg.toUtf8()); + rpp.setIncludePaths(includes); + CppTools::RawProjectPartFlags cProjectFlags; + cProjectFlags.commandLineFlags = flags; + rpp.setFlagsForC(cProjectFlags); - languages.unite(QSet::fromList(ppBuilder.createProjectPartsForFiles(transform(fg->sources, &FileName::toString)))); + CppTools::RawProjectPartFlags cxxProjectFlags; + cxxProjectFlags.commandLineFlags = flags; + rpp.setFlagsForCxx(cxxProjectFlags); + + rpp.setFiles(transform(fg->sources, &FileName::toString)); + + rpps.append(rpp); } qDeleteAll(m_projects); // Not used anymore! m_projects.clear(); m_targets.clear(); m_fileGroups.clear(); - - return languages; } void ServerModeReader::handleReply(const QVariantMap &data, const QString &inReplyTo) diff --git a/src/plugins/cmakeprojectmanager/servermodereader.h b/src/plugins/cmakeprojectmanager/servermodereader.h index fbefb58607c..36d75fc2ded 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.h +++ b/src/plugins/cmakeprojectmanager/servermodereader.h @@ -56,7 +56,7 @@ public: CMakeConfig takeParsedConfiguration() final; void generateProjectTree(CMakeListsNode *root, const QList &allFiles) final; - QSet updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) final; + void updateCodeModel(CppTools::RawProjectParts &rpps) final; private: void handleReply(const QVariantMap &data, const QString &inReplyTo); diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.cpp b/src/plugins/cmakeprojectmanager/tealeafreader.cpp index 836dad964d4..47ca819c1bd 100644 --- a/src/plugins/cmakeprojectmanager/tealeafreader.cpp +++ b/src/plugins/cmakeprojectmanager/tealeafreader.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -312,9 +311,8 @@ static void processCMakeIncludes(const CMakeBuildTarget &cbt, const ToolChain *t } } -QSet TeaLeafReader::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) +void TeaLeafReader::updateCodeModel(CppTools::RawProjectParts &rpps) { - QSet languages; const ToolChain *tcCxx = ToolChainManager::findToolChain(m_parameters.cxxToolChainId); const ToolChain *tcC = ToolChainManager::findToolChain(m_parameters.cToolChainId); const FileName sysroot = m_parameters.sysRoot; @@ -339,21 +337,24 @@ QSet TeaLeafReader::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) includePaths = transform(cbt.includeFiles, &FileName::toString); } includePaths += m_parameters.buildDirectory.toString(); - ppBuilder.setProjectFile(QString()); // No project file information available! - ppBuilder.setIncludePaths(includePaths); - ppBuilder.setCFlags(cflags); - ppBuilder.setCxxFlags(cxxflags); - ppBuilder.setDefines(cbt.defines); - ppBuilder.setDisplayName(cbt.title); + CppTools::RawProjectPart rpp; + rpp.setProjectFile(QString()); // No project file information available! + rpp.setIncludePaths(includePaths); - const QSet partLanguages - = QSet::fromList(ppBuilder.createProjectPartsForFiles( - transform(cbt.files, [](const FileName &fn) { return fn.toString(); }))); + CppTools::RawProjectPartFlags cProjectFlags; + cProjectFlags.commandLineFlags = cflags; + rpp.setFlagsForC(cProjectFlags); - languages.unite(partLanguages); + CppTools::RawProjectPartFlags cxxProjectFlags; + cxxProjectFlags.commandLineFlags = cxxflags; + rpp.setFlagsForCxx(cxxProjectFlags); + + rpp.setDefines(cbt.defines); + rpp.setDisplayName(cbt.title); + rpp.setFiles(transform(cbt.files, [](const FileName &fn) { return fn.toString(); })); + + rpps.append(rpp); } - return languages; - } void TeaLeafReader::cleanUpProcess() diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.h b/src/plugins/cmakeprojectmanager/tealeafreader.h index 4eca9b0af83..3aa258580a5 100644 --- a/src/plugins/cmakeprojectmanager/tealeafreader.h +++ b/src/plugins/cmakeprojectmanager/tealeafreader.h @@ -58,7 +58,7 @@ public: CMakeConfig takeParsedConfiguration() final; void generateProjectTree(CMakeListsNode *root, const QList &allFiles) final; - QSet updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) final; + void updateCodeModel(CppTools::RawProjectParts &rpps) final; private: void cleanUpProcess(); diff --git a/src/plugins/cpptools/builtinindexingsupport.cpp b/src/plugins/cpptools/builtinindexingsupport.cpp index c2ae6096c08..eadcda99bd2 100644 --- a/src/plugins/cpptools/builtinindexingsupport.cpp +++ b/src/plugins/cpptools/builtinindexingsupport.cpp @@ -133,7 +133,9 @@ void classifyFiles(const QSet &files, QStringList *headers, QStringList } } -void indexFindErrors(QFutureInterface &future, const ParseParams params) +void indexFindErrors(QFutureInterface &indexingFuture, + const QFutureInterface &superFuture, + const ParseParams params) { QStringList sources, headers; classifyFiles(params.sourceFiles, &headers, &sources); @@ -146,9 +148,7 @@ void indexFindErrors(QFutureInterface &future, const ParseParams params) timer.start(); for (int i = 0, end = files.size(); i < end ; ++i) { - if (future.isPaused()) - future.waitForResume(); - if (future.isCanceled()) + if (indexingFuture.isCanceled() || superFuture.isCanceled()) break; const QString file = files.at(i); @@ -170,7 +170,7 @@ void indexFindErrors(QFutureInterface &future, const ParseParams params) document->releaseSourceAndAST(); - future.setProgressValue(files.size() - (files.size() - (i + 1))); + indexingFuture.setProgressValue(files.size() - (files.size() - (i + 1))); } const QTime format = QTime(0, 0, 0, 0).addMSecs(timer.elapsed() + 500); @@ -178,7 +178,9 @@ void indexFindErrors(QFutureInterface &future, const ParseParams params) qDebug("FindErrorsIndexing: Finished after %s.", qPrintable(time)); } -void index(QFutureInterface &future, const ParseParams params) +void index(QFutureInterface &indexingFuture, + const QFutureInterface &superFuture, + const ParseParams params) { QScopedPointer sourceProcessor(CppModelManager::createSourceProcessor()); sourceProcessor->setFileSizeLimitInMb(params.indexerFileSizeLimitInMb); @@ -205,10 +207,7 @@ void index(QFutureInterface &future, const ParseParams params) const CPlusPlus::LanguageFeatures defaultFeatures = CPlusPlus::LanguageFeatures::defaultFeatures(); for (int i = 0; i < files.size(); ++i) { - if (future.isPaused()) - future.waitForResume(); - - if (future.isCanceled()) + if (indexingFuture.isCanceled() || superFuture.isCanceled()) break; const QString fileName = files.at(i); @@ -233,27 +232,29 @@ void index(QFutureInterface &future, const ParseParams params) sourceProcessor->setHeaderPaths(headerPaths); sourceProcessor->run(fileName); - future.setProgressValue(files.size() - sourceProcessor->todo().size()); + indexingFuture.setProgressValue(files.size() - sourceProcessor->todo().size()); if (isSourceFile) sourceProcessor->resetEnvironment(); } } -void parse(QFutureInterface &future, const ParseParams params) +void parse(QFutureInterface &indexingFuture, + const QFutureInterface &superFuture, + const ParseParams params) { const QSet &files = params.sourceFiles; if (files.isEmpty()) return; - future.setProgressRange(0, files.size()); + indexingFuture.setProgressRange(0, files.size()); if (FindErrorsIndexing) - indexFindErrors(future, params); + indexFindErrors(indexingFuture, superFuture, params); else - index(future, params); + index(indexingFuture, superFuture, params); - future.setProgressValue(files.size()); + indexingFuture.setProgressValue(files.size()); CppModelManager::instance()->finishedRefreshingSourceFiles(files); } @@ -345,8 +346,10 @@ BuiltinIndexingSupport::BuiltinIndexingSupport() BuiltinIndexingSupport::~BuiltinIndexingSupport() {} -QFuture BuiltinIndexingSupport::refreshSourceFiles(const QSet &sourceFiles, - CppModelManager::ProgressNotificationMode mode) +QFuture BuiltinIndexingSupport::refreshSourceFiles( + const QFutureInterface &superFuture, + const QSet &sourceFiles, + CppModelManager::ProgressNotificationMode mode) { CppModelManager *mgr = CppModelManager::instance(); @@ -357,7 +360,7 @@ QFuture BuiltinIndexingSupport::refreshSourceFiles(const QSet &so params.workingCopy.insert(mgr->configurationFileName(), mgr->definedMacros()); params.sourceFiles = sourceFiles; - QFuture result = Utils::runAsync(mgr->sharedThreadPool(), parse, params); + QFuture result = Utils::runAsync(mgr->sharedThreadPool(), parse, superFuture, params); if (m_synchronizer.futures().size() > 10) { QList > futures = m_synchronizer.futures(); diff --git a/src/plugins/cpptools/builtinindexingsupport.h b/src/plugins/cpptools/builtinindexingsupport.h index 82414338ecd..ad4f06d52e2 100644 --- a/src/plugins/cpptools/builtinindexingsupport.h +++ b/src/plugins/cpptools/builtinindexingsupport.h @@ -38,10 +38,11 @@ public: BuiltinIndexingSupport(); ~BuiltinIndexingSupport(); - virtual QFuture refreshSourceFiles(const QSet &sourceFiles, - CppModelManager::ProgressNotificationMode mode); - virtual SymbolSearcher *createSymbolSearcher(SymbolSearcher::Parameters parameters, - QSet fileNames); + QFuture refreshSourceFiles(const QFutureInterface &superFuture, + const QSet &sourceFiles, + CppModelManager::ProgressNotificationMode mode) override; + SymbolSearcher *createSymbolSearcher(SymbolSearcher::Parameters parameters, + QSet fileNames) override; public: static bool isFindErrorsIndexingActive(); diff --git a/src/plugins/cpptools/cppbaseprojectpartbuilder.cpp b/src/plugins/cpptools/cppbaseprojectpartbuilder.cpp deleted file mode 100644 index 194ed0df29a..00000000000 --- a/src/plugins/cpptools/cppbaseprojectpartbuilder.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "cppbaseprojectpartbuilder.h" - -#include "cppprojectfile.h" -#include "cppprojectfilecategorizer.h" -#include "projectinfo.h" - -#include -#include -#include - -#include - -namespace CppTools { - -BaseProjectPartBuilder::BaseProjectPartBuilder(ProjectInterface *project, - ProjectInfo &projectInfo) - : m_project(project) - , m_projectInfo(projectInfo) - , m_templatePart(new ProjectPart) -{ - QTC_CHECK(m_project); - m_templatePart->project = projectInfo.project(); - m_templatePart->displayName = m_project->displayName(); - m_templatePart->projectFile = m_project->projectFilePath(); -} - -void BaseProjectPartBuilder::setQtVersion(ProjectPart::QtVersion qtVersion) -{ - m_templatePart->qtVersion = qtVersion; -} - -void BaseProjectPartBuilder::setCFlags(const QStringList &flags) -{ - m_cFlags = flags; -} - -void BaseProjectPartBuilder::setCxxFlags(const QStringList &flags) -{ - m_cxxFlags = flags; -} - -void BaseProjectPartBuilder::setDefines(const QByteArray &defines) -{ - m_templatePart->projectDefines = defines; -} - -void BaseProjectPartBuilder::setHeaderPaths(const ProjectPartHeaderPaths &headerPaths) -{ - m_templatePart->headerPaths = headerPaths; -} - -void BaseProjectPartBuilder::setIncludePaths(const QStringList &includePaths) -{ - m_templatePart->headerPaths.clear(); - - foreach (const QString &includeFile, includePaths) { - ProjectPartHeaderPath hp(includeFile, ProjectPartHeaderPath::IncludePath); - - // The simple project managers are utterly ignorant of frameworks on OSX, and won't report - // framework paths. The work-around is to check if the include path ends in ".framework", - // and if so, add the parent directory as framework path. - if (includeFile.endsWith(QLatin1String(".framework"))) { - const int slashIdx = includeFile.lastIndexOf(QLatin1Char('/')); - if (slashIdx != -1) { - hp = ProjectPartHeaderPath(includeFile.left(slashIdx), - ProjectPartHeaderPath::FrameworkPath); - } - } - - m_templatePart->headerPaths += hp; - } -} - -void BaseProjectPartBuilder::setPreCompiledHeaders(const QStringList &preCompiledHeaders) -{ - m_templatePart->precompiledHeaders = preCompiledHeaders; -} - -void BaseProjectPartBuilder::setSelectedForBuilding(bool yesno) -{ - m_templatePart->selectedForBuilding = yesno; -} - -void BaseProjectPartBuilder::setProjectFile(const QString &projectFile) -{ - m_templatePart->projectFile = projectFile; -} - -void BaseProjectPartBuilder::setDisplayName(const QString &displayName) -{ - m_templatePart->displayName = displayName; -} - -void BaseProjectPartBuilder::setConfigFileName(const QString &configFileName) -{ - m_templatePart->projectConfigFile = configFileName; -} - -QList BaseProjectPartBuilder::createProjectPartsForFiles(const QStringList &filePaths, - FileClassifier fileClassifier) -{ - QList languages; - - ProjectFileCategorizer cat(m_templatePart->displayName, filePaths, fileClassifier); - - if (cat.hasParts()) { - if (cat.hasCxxSources()) { - languages += ProjectExplorer::Constants::CXX_LANGUAGE_ID; - createProjectPart(cat.cxxSources(), - cat.partName("C++"), - ProjectPart::LatestCxxVersion, - ProjectPart::NoExtensions); - } - - if (cat.hasObjcxxSources()) { - languages += ProjectExplorer::Constants::CXX_LANGUAGE_ID; - createProjectPart(cat.objcxxSources(), - cat.partName("Obj-C++"), - ProjectPart::LatestCxxVersion, - ProjectPart::ObjectiveCExtensions); - } - - if (cat.hasCSources()) { - languages += ProjectExplorer::Constants::C_LANGUAGE_ID; - createProjectPart(cat.cSources(), - cat.partName("C"), - ProjectPart::LatestCVersion, - ProjectPart::NoExtensions); - } - - if (cat.hasObjcSources()) { - languages += ProjectExplorer::Constants::C_LANGUAGE_ID; - createProjectPart(cat.objcSources(), - cat.partName("Obj-C"), - ProjectPart::LatestCVersion, - ProjectPart::ObjectiveCExtensions); - } - } - - return languages; -} - -namespace { - -class ToolChainEvaluator -{ -public: - ToolChainEvaluator(ProjectPart &projectPart, - const ToolChainInterface &toolChain) - : m_projectPart(projectPart) - , m_toolChain(toolChain) - , m_compilerFlags(toolChain.compilerFlags()) - { - } - - void evaluate() - { - mapLanguageVersion(); - mapLanguageExtensions(); - - addHeaderPaths(); - m_projectPart.toolchainDefines = m_toolChain.predefinedMacros(); - - m_projectPart.warningFlags = m_toolChain.warningFlags(); - m_projectPart.toolchainType = m_toolChain.type(); - m_projectPart.isMsvc2015Toolchain = m_toolChain.isMsvc2015Toolchain(); - m_projectPart.toolChainWordWidth = mapWordWith(m_toolChain.wordWidth()); - m_projectPart.toolChainTargetTriple = m_toolChain.targetTriple(); - } - -private: - static ProjectPart::ToolChainWordWidth mapWordWith(unsigned wordWidth) - { - return wordWidth == 64 - ? ProjectPart::WordWidth64Bit - : ProjectPart::WordWidth32Bit; - } - - void mapLanguageVersion() - { - using namespace ProjectExplorer; - ProjectPart::LanguageVersion &languageVersion = m_projectPart.languageVersion; - - if (m_compilerFlags & ToolChain::StandardC11) - languageVersion = ProjectPart::C11; - else if (m_compilerFlags & ToolChain::StandardC99) - languageVersion = ProjectPart::C99; - else if (m_compilerFlags & ToolChain::StandardCxx17) - languageVersion = ProjectPart::CXX17; - else if (m_compilerFlags & ToolChain::StandardCxx14) - languageVersion = ProjectPart::CXX14; - else if (m_compilerFlags & ToolChain::StandardCxx11) - languageVersion = ProjectPart::CXX11; - else if (m_compilerFlags & ToolChain::StandardCxx98) - languageVersion = ProjectPart::CXX98; - } - - void mapLanguageExtensions() - { - using namespace ProjectExplorer; - ProjectPart::LanguageExtensions &languageExtensions = m_projectPart.languageExtensions; - - if (m_compilerFlags & ToolChain::BorlandExtensions) - languageExtensions |= ProjectPart::BorlandExtensions; - if (m_compilerFlags & ToolChain::GnuExtensions) - languageExtensions |= ProjectPart::GnuExtensions; - if (m_compilerFlags & ToolChain::MicrosoftExtensions) - languageExtensions |= ProjectPart::MicrosoftExtensions; - if (m_compilerFlags & ToolChain::OpenMP) - languageExtensions |= ProjectPart::OpenMPExtensions; - if (m_compilerFlags & ToolChain::ObjectiveC) - languageExtensions |= ProjectPart::ObjectiveCExtensions; - } - - static ProjectPartHeaderPath toProjectPartHeaderPath( - const ProjectExplorer::HeaderPath &headerPath) - { - const ProjectPartHeaderPath::Type headerPathType = - headerPath.kind() == ProjectExplorer::HeaderPath::FrameworkHeaderPath - ? ProjectPartHeaderPath::FrameworkPath - : ProjectPartHeaderPath::IncludePath; - - return ProjectPartHeaderPath(headerPath.path(), headerPathType); - } - - void addHeaderPaths() - { - ProjectPartHeaderPaths &headerPaths = m_projectPart.headerPaths; - - foreach (const ProjectExplorer::HeaderPath &header, m_toolChain.systemHeaderPaths()) { - const ProjectPartHeaderPath headerPath = toProjectPartHeaderPath(header); - if (!headerPaths.contains(headerPath)) - headerPaths.push_back(headerPath); - } - } - -private: - ProjectPart &m_projectPart; - - const ToolChainInterface &m_toolChain; - const ProjectExplorer::ToolChain::CompilerFlags m_compilerFlags; -}; - -} // anynomous - -void BaseProjectPartBuilder::createProjectPart(const ProjectFiles &projectFiles, - const QString &partName, - ProjectPart::LanguageVersion languageVersion, - ProjectPart::LanguageExtensions languageExtensions) -{ - ProjectPart::Ptr part(m_templatePart->copy()); - part->displayName = partName; - part->files = projectFiles; - part->languageVersion = languageVersion; - QTC_ASSERT(part->project, return); - - // TODO: If not toolchain is set, show a warning - if (const ToolChainInterfacePtr toolChain = selectToolChain(languageVersion)) { - ToolChainEvaluator evaluator(*part.data(), *toolChain.get()); - evaluator.evaluate(); - } - - part->languageExtensions |= languageExtensions; - part->updateLanguageFeatures(); - - m_projectInfo.appendProjectPart(part); -} - -ToolChainInterfacePtr BaseProjectPartBuilder::selectToolChain( - ProjectPart::LanguageVersion languageVersion) -{ - ToolChainInterfacePtr toolChain = nullptr; - - if (languageVersion <= ProjectPart::LatestCVersion) - toolChain = m_project->toolChain(ProjectExplorer::Constants::C_LANGUAGE_ID, m_cFlags); - - if (!toolChain) // Use Cxx toolchain for C projects without C compiler in kit and for C++ code - toolChain = m_project->toolChain(ProjectExplorer::Constants::CXX_LANGUAGE_ID, m_cxxFlags); - - return toolChain; -} - -} // namespace CppTools diff --git a/src/plugins/cpptools/cppindexingsupport.h b/src/plugins/cpptools/cppindexingsupport.h index e97bb50f675..880e88eeac1 100644 --- a/src/plugins/cpptools/cppindexingsupport.h +++ b/src/plugins/cpptools/cppindexingsupport.h @@ -78,8 +78,9 @@ class CPPTOOLS_EXPORT CppIndexingSupport public: virtual ~CppIndexingSupport() = 0; - virtual QFuture refreshSourceFiles(const QSet &sourceFiles, - CppModelManager::ProgressNotificationMode mode) = 0; + virtual QFuture refreshSourceFiles(const QFutureInterface &superFuture, + const QSet &sourceFiles, + CppModelManager::ProgressNotificationMode mode) = 0; virtual SymbolSearcher *createSymbolSearcher(SymbolSearcher::Parameters parameters, QSet fileNames) = 0; }; diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index 965557549b0..4cb5ce107e1 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -630,6 +630,14 @@ static QSet tooBigFilesRemoved(const QSet &files, int fileSize QFuture CppModelManager::updateSourceFiles(const QSet &sourceFiles, ProgressNotificationMode mode) +{ + const QFutureInterface dummy; + return updateSourceFiles(dummy, sourceFiles, mode); +} + +QFuture CppModelManager::updateSourceFiles(const QFutureInterface &superFuture, + const QSet &sourceFiles, + ProgressNotificationMode mode) { if (sourceFiles.isEmpty() || !d->m_indexerEnabled) return QFuture(); @@ -637,8 +645,8 @@ QFuture CppModelManager::updateSourceFiles(const QSet &sourceFile const QSet filteredFiles = tooBigFilesRemoved(sourceFiles, indexerFileSizeLimitInMb()); if (d->m_indexingSupporter) - d->m_indexingSupporter->refreshSourceFiles(filteredFiles, mode); - return d->m_internalIndexingSupport->refreshSourceFiles(filteredFiles, mode); + d->m_indexingSupporter->refreshSourceFiles(superFuture, filteredFiles, mode); + return d->m_internalIndexingSupport->refreshSourceFiles(superFuture, filteredFiles, mode); } QList CppModelManager::projectInfos() const @@ -774,23 +782,25 @@ void CppModelManager::recalculateProjectPartMappings() d->m_symbolFinder.clearCache(); } -void CppModelManager::watchForCanceledProjectIndexer(QFuture future, +void CppModelManager::watchForCanceledProjectIndexer(const QVector> &futures, ProjectExplorer::Project *project) { d->m_projectToIndexerCanceled.insert(project, false); - if (future.isCanceled() || future.isFinished()) - return; + for (const QFuture &future : futures) { + if (future.isCanceled() || future.isFinished()) + continue; - QFutureWatcher *watcher = new QFutureWatcher(); - connect(watcher, &QFutureWatcher::canceled, this, [this, project]() { - if (d->m_projectToIndexerCanceled.contains(project)) // Project not yet removed - d->m_projectToIndexerCanceled.insert(project, true); - }); - connect(watcher, &QFutureWatcher::finished, this, [watcher]() { - watcher->deleteLater(); - }); - watcher->setFuture(future); + QFutureWatcher *watcher = new QFutureWatcher(); + connect(watcher, &QFutureWatcher::canceled, this, [this, project]() { + if (d->m_projectToIndexerCanceled.contains(project)) // Project not yet removed + d->m_projectToIndexerCanceled.insert(project, true); + }); + connect(watcher, &QFutureWatcher::finished, this, [watcher]() { + watcher->deleteLater(); + }); + watcher->setFuture(future); + } } void CppModelManager::updateCppEditorDocuments(bool projectsUpdated) const @@ -823,6 +833,13 @@ void CppModelManager::updateCppEditorDocuments(bool projectsUpdated) const } QFuture CppModelManager::updateProjectInfo(const ProjectInfo &newProjectInfo) +{ + QFutureInterface dummy; + return updateProjectInfo(dummy, newProjectInfo); +} + +QFuture CppModelManager::updateProjectInfo(QFutureInterface &futureInterface, + const ProjectInfo &newProjectInfo) { if (!newProjectInfo.isValid()) return QFuture(); @@ -908,10 +925,10 @@ QFuture CppModelManager::updateProjectInfo(const ProjectInfo &newProjectIn updateCppEditorDocuments(/*projectsUpdated = */ true); // Trigger reindexing - QFuture indexerFuture = updateSourceFiles(filesToReindex, ForcedProgressNotification); - watchForCanceledProjectIndexer(indexerFuture, project); - - return indexerFuture; + const QFuture indexingFuture = updateSourceFiles(futureInterface, filesToReindex, + ForcedProgressNotification); + watchForCanceledProjectIndexer({futureInterface.future(), indexingFuture}, project); + return indexingFuture; } ProjectInfo CppModelManager::updateCompilerCallDataForProject( diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 6fe5897f9a2..ce2a042bc9d 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -86,7 +86,10 @@ public: }; QFuture updateSourceFiles(const QSet &sourceFiles, - ProgressNotificationMode mode = ReservedProgressNotification); + ProgressNotificationMode mode = ReservedProgressNotification); + QFuture updateSourceFiles(const QFutureInterface &superFuture, + const QSet &sourceFiles, + ProgressNotificationMode mode = ReservedProgressNotification); void updateCppEditorDocuments(bool projectsUpdated = false) const; WorkingCopy workingCopy() const; QByteArray codeModelConfiguration() const; @@ -94,6 +97,9 @@ public: QList projectInfos() const; ProjectInfo projectInfo(ProjectExplorer::Project *project) const; QFuture updateProjectInfo(const ProjectInfo &newProjectInfo); + QFuture updateProjectInfo(QFutureInterface &futureInterface, + const ProjectInfo &newProjectInfo); + ProjectInfo updateCompilerCallDataForProject(ProjectExplorer::Project *project, ProjectInfo::CompilerCallData &compilerCallData); @@ -210,7 +216,8 @@ private: void initializeBuiltinModelManagerSupport(); void delayedGC(); void recalculateProjectPartMappings(); - void watchForCanceledProjectIndexer(QFuture future, ProjectExplorer::Project *project); + void watchForCanceledProjectIndexer(const QVector > &futures, + ProjectExplorer::Project *project); void replaceSnapshot(const CPlusPlus::Snapshot &newSnapshot); void removeFilesFromSnapshot(const QSet &removedFiles); diff --git a/src/plugins/cpptools/cppprojectfilecategorizer.cpp b/src/plugins/cpptools/cppprojectfilecategorizer.cpp index bf0666e9afb..063dfd5dbac 100644 --- a/src/plugins/cpptools/cppprojectfilecategorizer.cpp +++ b/src/plugins/cpptools/cppprojectfilecategorizer.cpp @@ -29,7 +29,7 @@ namespace CppTools { ProjectFileCategorizer::ProjectFileCategorizer(const QString &projectPartName, const QStringList &filePaths, - ProjectPartBuilder::FileClassifier fileClassifier) + FileClassifier fileClassifier) : m_partName(projectPartName) { const QStringList ambiguousHeaders = classifyFiles(filePaths, fileClassifier); @@ -50,9 +50,8 @@ QString ProjectFileCategorizer::partName(const QString &languageName) const return m_partName; } -QStringList ProjectFileCategorizer::classifyFiles( - const QStringList &filePaths, - ProjectPartBuilder::FileClassifier fileClassifier) +QStringList ProjectFileCategorizer::classifyFiles(const QStringList &filePaths, + FileClassifier fileClassifier) { QStringList ambiguousHeaders; diff --git a/src/plugins/cpptools/cppprojectfilecategorizer.h b/src/plugins/cpptools/cppprojectfilecategorizer.h index a45c9bf99bc..0d52767876a 100644 --- a/src/plugins/cpptools/cppprojectfilecategorizer.h +++ b/src/plugins/cpptools/cppprojectfilecategorizer.h @@ -26,7 +26,7 @@ #pragma once #include "cppprojectfile.h" -#include "projectpartbuilder.h" +#include "cpprawprojectpart.h" #include #include @@ -36,7 +36,7 @@ namespace CppTools { class ProjectFileCategorizer { public: - using FileClassifier = ProjectPartBuilder::FileClassifier; + using FileClassifier = RawProjectPart::FileClassifier; public: ProjectFileCategorizer(const QString &projectPartName, diff --git a/src/plugins/cpptools/cppprojectinfogenerator.cpp b/src/plugins/cpptools/cppprojectinfogenerator.cpp new file mode 100644 index 00000000000..56216ccd4a6 --- /dev/null +++ b/src/plugins/cpptools/cppprojectinfogenerator.cpp @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "cppprojectinfogenerator.h" + +#include "cppprojectfilecategorizer.h" + +#include + +namespace CppTools { +namespace Internal { + +namespace { + +class ToolChainEvaluator +{ +public: + ToolChainEvaluator(ProjectPart &projectPart, + const RawProjectPartFlags &flags, + const ToolChainInfo &tcInfo) + : m_projectPart(projectPart) + , m_flags(flags) + , m_tcInfo(tcInfo) + { + } + + void evaluate() + { + m_projectPart.toolchainType = m_tcInfo.type; + m_projectPart.isMsvc2015Toolchain = m_tcInfo.isMsvc2015ToolChain; + m_projectPart.toolChainWordWidth = mapWordWith(m_tcInfo.wordWidth); + m_projectPart.toolChainTargetTriple = m_tcInfo.targetTriple; + + m_projectPart.warningFlags = m_flags.warningFlags; + + mapLanguageVersion(); + mapLanguageExtensions(); + + addHeaderPaths(); + addDefines(); + } + +private: + static ProjectPart::ToolChainWordWidth mapWordWith(unsigned wordWidth) + { + return wordWidth == 64 + ? ProjectPart::WordWidth64Bit + : ProjectPart::WordWidth32Bit; + } + + void mapLanguageVersion() + { + using namespace ProjectExplorer; + + const ToolChain::CompilerFlags &compilerFlags = m_flags.compilerFlags; + ProjectPart::LanguageVersion &languageVersion = m_projectPart.languageVersion; + + if (compilerFlags & ToolChain::StandardC11) + languageVersion = ProjectPart::C11; + else if (compilerFlags & ToolChain::StandardC99) + languageVersion = ProjectPart::C99; + else if (compilerFlags & ToolChain::StandardCxx17) + languageVersion = ProjectPart::CXX17; + else if (compilerFlags & ToolChain::StandardCxx14) + languageVersion = ProjectPart::CXX14; + else if (compilerFlags & ToolChain::StandardCxx11) + languageVersion = ProjectPart::CXX11; + else if (compilerFlags & ToolChain::StandardCxx98) + languageVersion = ProjectPart::CXX98; + } + + void mapLanguageExtensions() + { + using namespace ProjectExplorer; + + const ToolChain::CompilerFlags &compilerFlags = m_flags.compilerFlags; + ProjectPart::LanguageExtensions &languageExtensions = m_projectPart.languageExtensions; + + if (compilerFlags & ToolChain::BorlandExtensions) + languageExtensions |= ProjectPart::BorlandExtensions; + if (compilerFlags & ToolChain::GnuExtensions) + languageExtensions |= ProjectPart::GnuExtensions; + if (compilerFlags & ToolChain::MicrosoftExtensions) + languageExtensions |= ProjectPart::MicrosoftExtensions; + if (compilerFlags & ToolChain::OpenMP) + languageExtensions |= ProjectPart::OpenMPExtensions; + if (compilerFlags & ToolChain::ObjectiveC) + languageExtensions |= ProjectPart::ObjectiveCExtensions; + } + + static ProjectPartHeaderPath toProjectPartHeaderPath( + const ProjectExplorer::HeaderPath &headerPath) + { + const ProjectPartHeaderPath::Type headerPathType = + headerPath.kind() == ProjectExplorer::HeaderPath::FrameworkHeaderPath + ? ProjectPartHeaderPath::FrameworkPath + : ProjectPartHeaderPath::IncludePath; + + return ProjectPartHeaderPath(headerPath.path(), headerPathType); + } + + void addHeaderPaths() + { + if (!m_tcInfo.headerPathsRunner) + return; // No compiler set in kit. + + const QList systemHeaderPaths + = m_tcInfo.headerPathsRunner(m_flags.commandLineFlags, + m_tcInfo.sysRoothPath); + + ProjectPartHeaderPaths &headerPaths = m_projectPart.headerPaths; + for (const ProjectExplorer::HeaderPath &header : systemHeaderPaths) { + const ProjectPartHeaderPath headerPath = toProjectPartHeaderPath(header); + if (!headerPaths.contains(headerPath)) + headerPaths.push_back(headerPath); + } + } + + void addDefines() + { + if (!m_tcInfo.predefinedMacrosRunner) + return; // No compiler set in kit. + + m_projectPart.toolchainDefines = m_tcInfo.predefinedMacrosRunner(m_flags.commandLineFlags); + } + +private: + ProjectPart &m_projectPart; + const RawProjectPartFlags &m_flags; + const ToolChainInfo &m_tcInfo; +}; + +} // anonymous namespace + +ProjectInfoGenerator::ProjectInfoGenerator(const QFutureInterface &futureInterface, + const ProjectUpdateInfo &projectUpdateInfo) + : m_futureInterface(futureInterface) + , m_projectUpdateInfo(projectUpdateInfo) +{ +} + +ProjectInfo ProjectInfoGenerator::generate() +{ + m_projectInfo = ProjectInfo(m_projectUpdateInfo.project); + + for (const RawProjectPart &rpp : m_projectUpdateInfo.rawProjectParts) { + if (m_futureInterface.isCanceled()) + return ProjectInfo(); + + createProjectParts(rpp); + } + + return m_projectInfo; +} + +static ProjectPart::Ptr projectPartFromRawProjectPart(const RawProjectPart &rawProjectPart) +{ + ProjectPart::Ptr part(new ProjectPart); + part->projectFile = rawProjectPart.projectFile; + part->projectConfigFile = rawProjectPart.projectConfigFile; + part->qtVersion = rawProjectPart.qtVersion; + part->projectDefines = rawProjectPart.projectDefines; + part->headerPaths = rawProjectPart.headerPaths; + part->precompiledHeaders = rawProjectPart.precompiledHeaders; + part->selectedForBuilding = rawProjectPart.selectedForBuilding; + + return part; +} + +void ProjectInfoGenerator::createProjectParts(const RawProjectPart &rawProjectPart) +{ + ProjectFileCategorizer cat(rawProjectPart.displayName, + rawProjectPart.files, + rawProjectPart.fileClassifier); + + if (cat.hasParts()) { + const ProjectPart::Ptr part = projectPartFromRawProjectPart(rawProjectPart); + + if (cat.hasCxxSources()) { + createProjectPart(rawProjectPart, + part, + cat.cxxSources(), + cat.partName("C++"), + ProjectPart::LatestCxxVersion, + ProjectPart::NoExtensions); + } + + if (cat.hasObjcxxSources()) { + createProjectPart(rawProjectPart, + part, + cat.objcxxSources(), + cat.partName("Obj-C++"), + ProjectPart::LatestCxxVersion, + ProjectPart::ObjectiveCExtensions); + } + + if (cat.hasCSources()) { + createProjectPart(rawProjectPart, + part, + cat.cSources(), + cat.partName("C"), + ProjectPart::LatestCVersion, + ProjectPart::NoExtensions); + } + + if (cat.hasObjcSources()) { + createProjectPart(rawProjectPart, + part, + cat.objcSources(), + cat.partName("Obj-C"), + ProjectPart::LatestCVersion, + ProjectPart::ObjectiveCExtensions); + } + } +} + +void ProjectInfoGenerator::createProjectPart(const RawProjectPart &rawProjectPart, + const ProjectPart::Ptr &templateProjectPart, + const ProjectFiles &projectFiles, + const QString &partName, + ProjectPart::LanguageVersion languageVersion, + ProjectPart::LanguageExtensions languageExtensions) +{ + ProjectPart::Ptr part(templateProjectPart->copy()); + part->displayName = partName; + part->files = projectFiles; + part->languageVersion = languageVersion; + + RawProjectPartFlags flags; + ToolChainInfo tcInfo; + if (languageVersion <= ProjectPart::LatestCVersion) { + flags = rawProjectPart.flagsForC; + tcInfo = m_projectUpdateInfo.cToolChainInfo; + } + // Use Cxx toolchain for C projects without C compiler in kit and for C++ code + if (!tcInfo.isValid()) { + flags = rawProjectPart.flagsForCxx; + tcInfo = m_projectUpdateInfo.cxxToolChainInfo; + } + // TODO: If no toolchain is set, show a warning + ToolChainEvaluator evaluator(*part.data(), flags, tcInfo); + evaluator.evaluate(); + + part->languageExtensions |= languageExtensions; + part->updateLanguageFeatures(); + + m_projectInfo.appendProjectPart(part); +} + +} // namespace Internal +} // namespace CppTools diff --git a/src/plugins/cpptools/cppprojectinfogenerator.h b/src/plugins/cpptools/cppprojectinfogenerator.h new file mode 100644 index 00000000000..f1972cd5c2c --- /dev/null +++ b/src/plugins/cpptools/cppprojectinfogenerator.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "projectinfo.h" + +#include + +namespace CppTools { +namespace Internal { + +class ProjectInfoGenerator +{ +public: + ProjectInfoGenerator(const QFutureInterface &futureInterface, + const ProjectUpdateInfo &projectUpdateInfo); + + ProjectInfo generate(); + +private: + void createProjectParts(const RawProjectPart &rawProjectPart); + void createProjectPart(const RawProjectPart &rawProjectPart, + const ProjectPart::Ptr &templateProjectPart, + const ProjectFiles &projectFiles, + const QString &partName, + ProjectPart::LanguageVersion languageVersion, + ProjectPart::LanguageExtensions languageExtensions); + +private: + const QFutureInterface &m_futureInterface; + const ProjectUpdateInfo &m_projectUpdateInfo; + + ProjectInfo m_projectInfo; +}; +} // namespace Internal +} // namespace CppTools diff --git a/src/plugins/cpptools/cppprojectupdater.cpp b/src/plugins/cpptools/cppprojectupdater.cpp new file mode 100644 index 00000000000..33a2b1df585 --- /dev/null +++ b/src/plugins/cpptools/cppprojectupdater.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "cppprojectupdater.h" + +#include "cppmodelmanager.h" +#include "cppprojectinfogenerator.h" + +#include + +#include +#include + +namespace CppTools { + +CppProjectUpdater::CppProjectUpdater(ProjectExplorer::Project *project) + : m_project(project) +{ + connect(&m_generateFutureWatcher, &QFutureWatcher::finished, + this, &CppProjectUpdater::onProjectInfoGenerated); +} + +CppProjectUpdater::~CppProjectUpdater() +{ + cancelAndWaitForFinished(); +} + +void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo) +{ + // Stop previous update. + cancel(); + m_futureInterface.waitForFinished(); + m_futureInterface = QFutureInterface(); + + m_projectUpdateInfo = projectUpdateInfo; + + // Ensure that we do not operate on a deleted toolchain. + using namespace ProjectExplorer; + connect(ToolChainManager::instance(), &ToolChainManager::toolChainRemoved, + this, &CppProjectUpdater::onToolChainRemoved); + + // Run the project info generator in a worker thread and continue if that one is finished. + const QFutureInterface &futureInterface = m_futureInterface; + const QFuture future = Utils::runAsync([=]() { + Internal::ProjectInfoGenerator generator(futureInterface, projectUpdateInfo); + return generator.generate(); + }); + m_generateFutureWatcher.setFuture(future); +} + +void CppProjectUpdater::cancel() +{ + disconnect(&m_generateFutureWatcher); + m_futureInterface.cancel(); +} + +void CppProjectUpdater::cancelAndWaitForFinished() +{ + cancel(); + m_futureInterface.waitForFinished(); +} + +void CppProjectUpdater::onToolChainRemoved(ProjectExplorer::ToolChain *t) +{ + QTC_ASSERT(t, return); + if (t == m_projectUpdateInfo.cToolChain || t == m_projectUpdateInfo.cxxToolChain) + cancelAndWaitForFinished(); +} + +void CppProjectUpdater::onProjectInfoGenerated() +{ + // From now on we do not access the toolchain anymore, so disconnect. + using namespace ProjectExplorer; + disconnect(ToolChainManager::instance(), &ToolChainManager::toolChainRemoved, + this, &CppProjectUpdater::onToolChainRemoved); + + if (m_futureInterface.isCanceled()) + return; + + QFuture future = CppModelManager::instance() + ->updateProjectInfo(m_futureInterface, m_generateFutureWatcher.result()); + QTC_CHECK(future != QFuture()); + + const ProjectInfo projectInfo = CppModelManager::instance()->projectInfo(m_project); + QTC_CHECK(projectInfo.isValid()); + emit projectInfoUpdated(projectInfo); +} + +} // namespace CppTools diff --git a/src/plugins/cpptools/cppprojectinterface.h b/src/plugins/cpptools/cppprojectupdater.h similarity index 53% rename from src/plugins/cpptools/cppprojectinterface.h rename to src/plugins/cpptools/cppprojectupdater.h index dd03430cb82..60e470b0f73 100644 --- a/src/plugins/cpptools/cppprojectinterface.h +++ b/src/plugins/cpptools/cppprojectupdater.h @@ -25,55 +25,45 @@ #pragma once -#include +#include "cpptools_global.h" +#include "projectinfo.h" -#include +#include -QT_BEGIN_NAMESPACE -class QString; -QT_END_NAMESPACE - -namespace Core { -class Id; -} - -namespace ProjectExplorer { -class Project; -class ToolChain; -} +#include +#include namespace CppTools { -class ToolChainInterface +class ProjectInfo; +class ProjectUpdateInfo; + +class CPPTOOLS_EXPORT CppProjectUpdater : public QObject { + Q_OBJECT + public: - virtual ~ToolChainInterface() {} + CppProjectUpdater(ProjectExplorer::Project *project); + ~CppProjectUpdater(); - virtual Core::Id type() const = 0; - virtual bool isMsvc2015Toolchain() const = 0; + void update(const ProjectUpdateInfo &projectUpdateInfo); + void cancel(); - virtual unsigned wordWidth() const = 0; - virtual QString targetTriple() const = 0; +signals: + void projectInfoUpdated(const ProjectInfo &projectInfo); - virtual QByteArray predefinedMacros() const = 0; - virtual QList systemHeaderPaths() const = 0; +private: + void cancelAndWaitForFinished(); - virtual ProjectExplorer::WarningFlags warningFlags() const = 0; - virtual ProjectExplorer::ToolChain::CompilerFlags compilerFlags() const = 0; -}; + void onToolChainRemoved(ProjectExplorer::ToolChain *); + void onProjectInfoGenerated(); -using ToolChainInterfacePtr = std::unique_ptr; +private: + ProjectExplorer::Project * const m_project; + ProjectUpdateInfo m_projectUpdateInfo; -class ProjectInterface -{ -public: - virtual ~ProjectInterface() {} - - virtual QString displayName() const = 0; - virtual QString projectFilePath() const = 0; - - virtual ToolChainInterfacePtr toolChain(Core::Id language, - const QStringList &commandLineFlags) const = 0; + QFutureInterface m_futureInterface; + QFutureWatcher m_generateFutureWatcher; }; } // namespace CppTools diff --git a/src/plugins/cpptools/cpprawprojectpart.cpp b/src/plugins/cpptools/cpprawprojectpart.cpp new file mode 100644 index 00000000000..4df3458576b --- /dev/null +++ b/src/plugins/cpptools/cpprawprojectpart.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "cpprawprojectpart.h" + +#include +#include +#include + +namespace CppTools { + +RawProjectPartFlags::RawProjectPartFlags(const ProjectExplorer::ToolChain *toolChain, + const QStringList &commandLineFlags) +{ + // Keep the following cheap/non-blocking for the ui thread. Expensive + // operations are encapsulated in ToolChainInfo as "runners". + if (toolChain) { + this->commandLineFlags = commandLineFlags; + warningFlags = toolChain->warningFlags(commandLineFlags); + compilerFlags = toolChain->compilerFlags(commandLineFlags); + } +} + +void RawProjectPart::setDisplayName(const QString &displayName) +{ + this->displayName = displayName; +} + +void RawProjectPart::setFiles(const QStringList &files, FileClassifier fileClassifier) +{ + this->files = files; + this->fileClassifier = fileClassifier; +} + +void RawProjectPart::setProjectFile(const QString &projectFile) +{ + this->projectFile = projectFile; +} + +void RawProjectPart::setConfigFileName(const QString &configFileName) +{ + this->projectConfigFile = configFileName; +} + +void RawProjectPart::setQtVersion(ProjectPart::QtVersion qtVersion) +{ + this->qtVersion = qtVersion; +} + +void RawProjectPart::setDefines(const QByteArray &defines) +{ + this->projectDefines = defines; +} + +void RawProjectPart::setHeaderPaths(const ProjectPartHeaderPaths &headerPaths) +{ + this->headerPaths = headerPaths; +} + +void RawProjectPart::setIncludePaths(const QStringList &includePaths) +{ + headerPaths.clear(); + + foreach (const QString &includeFile, includePaths) { + ProjectPartHeaderPath hp(includeFile, ProjectPartHeaderPath::IncludePath); + + // The simple project managers are utterly ignorant of frameworks on macOS, and won't report + // framework paths. The work-around is to check if the include path ends in ".framework", + // and if so, add the parent directory as framework path. + if (includeFile.endsWith(QLatin1String(".framework"))) { + const int slashIdx = includeFile.lastIndexOf(QLatin1Char('/')); + if (slashIdx != -1) { + hp = ProjectPartHeaderPath(includeFile.left(slashIdx), + ProjectPartHeaderPath::FrameworkPath); + } + } + + headerPaths += hp; + } +} + +void RawProjectPart::setPreCompiledHeaders(const QStringList &preCompiledHeaders) +{ + this->precompiledHeaders = preCompiledHeaders; +} + +void RawProjectPart::setSelectedForBuilding(bool yesno) +{ + this->selectedForBuilding = yesno; +} + +void RawProjectPart::setFlagsForC(const RawProjectPartFlags &flags) +{ + flagsForC = flags; +} + +void RawProjectPart::setFlagsForCxx(const RawProjectPartFlags &flags) +{ + flagsForCxx = flags; +} + +} // namespace CppTools diff --git a/src/plugins/cpptools/cppbaseprojectpartbuilder.h b/src/plugins/cpptools/cpprawprojectpart.h similarity index 56% rename from src/plugins/cpptools/cppbaseprojectpartbuilder.h rename to src/plugins/cpptools/cpprawprojectpart.h index 779053dfbc7..7e6d36f4599 100644 --- a/src/plugins/cpptools/cppbaseprojectpartbuilder.h +++ b/src/plugins/cpptools/cpprawprojectpart.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -26,32 +26,45 @@ #pragma once #include "cpptools_global.h" - -#include "cppprojectinterface.h" #include "projectpart.h" +#include + #include -#include namespace CppTools { -class ProjectInfo; - -class CPPTOOLS_EXPORT BaseProjectPartBuilder +class CPPTOOLS_EXPORT RawProjectPartFlags { public: - BaseProjectPartBuilder(ProjectInterface *project, ProjectInfo &projectInfo); + RawProjectPartFlags() = default; + RawProjectPartFlags(const ProjectExplorer::ToolChain *toolChain, + const QStringList &commandLineFlags); + +public: + QStringList commandLineFlags; + // The following are deduced from commandLineFlags. + ProjectExplorer::WarningFlags warningFlags = ProjectExplorer::WarningFlags::Default; + ProjectExplorer::ToolChain::CompilerFlags compilerFlags + = ProjectExplorer::ToolChain::CompilerFlag::NoFlags; +}; + +class CPPTOOLS_EXPORT RawProjectPart +{ +public: + RawProjectPart() {} void setDisplayName(const QString &displayName); + // FileClassifier must be thread-safe. + using FileClassifier = std::function; + void setFiles(const QStringList &files, FileClassifier fileClassifier = FileClassifier()); + void setProjectFile(const QString &projectFile); void setConfigFileName(const QString &configFileName); void setQtVersion(ProjectPart::QtVersion qtVersion); - void setCFlags(const QStringList &flags); - void setCxxFlags(const QStringList &flags); - void setDefines(const QByteArray &defines); void setHeaderPaths(const ProjectPartHeaderPaths &headerPaths); void setIncludePaths(const QStringList &includePaths); @@ -60,24 +73,26 @@ public: void setSelectedForBuilding(bool yesno); - using FileClassifier = std::function; - QList createProjectPartsForFiles(const QStringList &filePaths, - FileClassifier fileClassifier = FileClassifier()); + void setFlagsForC(const RawProjectPartFlags &flags); + void setFlagsForCxx(const RawProjectPartFlags &flags); -private: - void createProjectPart(const ProjectFiles &projectFiles, - const QString &partName, - ProjectPart::LanguageVersion languageVersion, - ProjectPart::LanguageExtensions languageExtensions); - ToolChainInterfacePtr selectToolChain(ProjectPart::LanguageVersion languageVersion); +public: + QString displayName; + QString projectFile; + QString projectConfigFile; // currently only used by the Generic Project Manager + QStringList precompiledHeaders; + ProjectPartHeaderPaths headerPaths; + QByteArray projectDefines; + ProjectPart::QtVersion qtVersion = ProjectPart::UnknownQt; + bool selectedForBuilding = true; -private: - std::unique_ptr m_project; - ProjectInfo &m_projectInfo; + RawProjectPartFlags flagsForC; + RawProjectPartFlags flagsForCxx; - ProjectPart::Ptr m_templatePart; - QStringList m_cFlags; - QStringList m_cxxFlags; + QStringList files; + FileClassifier fileClassifier; }; +using RawProjectParts = QVector; + } // namespace CppTools diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index f65ffdd7645..3fffe2dfd3d 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -42,7 +42,9 @@ HEADERS += \ cppmodelmanagersupportinternal.h \ cpppointerdeclarationformatter.h \ cppprojectfile.h \ + cppprojectupdater.h \ cppqtstyleindenter.h \ + cpprawprojectpart.h \ cpprefactoringchanges.h \ cppselectionchanger.h \ cppsemanticinfo.h \ @@ -76,13 +78,11 @@ HEADERS += \ projectpart.h \ projectpartheaderpath.h \ projectinfo.h \ - projectpartbuilder.h \ + cppprojectinfogenerator.h \ compileroptionsbuilder.h \ refactoringengineinterface.h \ cppprojectfilecategorizer.h \ clangcompileroptionsbuilder.h \ - cppprojectinterface.h \ - cppbaseprojectpartbuilder.h \ cppprojectpartchooser.h \ SOURCES += \ @@ -125,7 +125,9 @@ SOURCES += \ cppmodelmanagersupportinternal.cpp \ cpppointerdeclarationformatter.cpp \ cppprojectfile.cpp \ + cppprojectupdater.cpp \ cppqtstyleindenter.cpp \ + cpprawprojectpart.cpp \ cpprefactoringchanges.cpp \ cppselectionchanger.cpp \ cppsemanticinfo.cpp \ @@ -154,10 +156,9 @@ SOURCES += \ cpptoolsbridgeqtcreatorimplementation.cpp \ projectpart.cpp \ projectinfo.cpp \ - projectpartbuilder.cpp \ + cppprojectinfogenerator.cpp \ compileroptionsbuilder.cpp \ cppprojectfilecategorizer.cpp \ - cppbaseprojectpartbuilder.cpp \ clangcompileroptionsbuilder.cpp \ cppprojectpartchooser.cpp \ diff --git a/src/plugins/cpptools/cpptools.qbs b/src/plugins/cpptools/cpptools.qbs index a812ca1c12e..6bfb639c5ef 100644 --- a/src/plugins/cpptools/cpptools.qbs +++ b/src/plugins/cpptools/cpptools.qbs @@ -51,8 +51,6 @@ Project { "clangdiagnosticconfigswidget.ui", "compileroptionsbuilder.cpp", "compileroptionsbuilder.h", - "cppbaseprojectpartbuilder.cpp", - "cppbaseprojectpartbuilder.h", "cppchecksymbols.cpp", "cppchecksymbols.h", "cppclassesfilter.cpp", @@ -118,11 +116,16 @@ Project { "cppprojectfile.h", "cppprojectfilecategorizer.cpp", "cppprojectfilecategorizer.h", - "cppprojectinterface.h", + "cppprojectinfogenerator.cpp", + "cppprojectinfogenerator.h", "cppprojectpartchooser.cpp", "cppprojectpartchooser.h", + "cppprojectupdater.cpp", + "cppprojectupdater.h", "cppqtstyleindenter.cpp", "cppqtstyleindenter.h", + "cpprawprojectpart.cpp", + "cpprawprojectpart.h", "cpprefactoringchanges.cpp", "cpprefactoringchanges.h", "cppselectionchanger.cpp", @@ -170,8 +173,6 @@ Project { "projectinfo.h", "projectpart.cpp", "projectpart.h", - "projectpartbuilder.cpp", - "projectpartbuilder.h", "projectpartheaderpath.h", "searchsymbols.cpp", "searchsymbols.h", diff --git a/src/plugins/cpptools/cpptoolsunittestfiles.pri b/src/plugins/cpptools/cpptoolsunittestfiles.pri index 317ba52b708..6960ccbde94 100644 --- a/src/plugins/cpptools/cpptoolsunittestfiles.pri +++ b/src/plugins/cpptools/cpptoolsunittestfiles.pri @@ -15,9 +15,8 @@ HEADERS += \ $$PWD/compileroptionsbuilder.h \ $$PWD/cppprojectfilecategorizer.h \ $$PWD/clangcompileroptionsbuilder.h \ - $$PWD/cppbaseprojectpartbuilder.h \ $$PWD/projectinfo.h \ - $$PWD/cppprojectinterface.h \ + $$PWD/cppprojectinfogenerator.cpp \ $$PWD/cppprojectpartchooser.h \ SOURCES += \ @@ -27,6 +26,6 @@ SOURCES += \ $$PWD/compileroptionsbuilder.cpp \ $$PWD/cppprojectfilecategorizer.cpp \ $$PWD/clangcompileroptionsbuilder.cpp \ - $$PWD/cppbaseprojectpartbuilder.cpp \ $$PWD/projectinfo.cpp \ + $$PWD/cppprojectinfogenerator.cpp \ $$PWD/cppprojectpartchooser.cpp \ diff --git a/src/plugins/cpptools/projectinfo.cpp b/src/plugins/cpptools/projectinfo.cpp index 919cbbbc9f2..e0db5fd54f3 100644 --- a/src/plugins/cpptools/projectinfo.cpp +++ b/src/plugins/cpptools/projectinfo.cpp @@ -25,10 +25,47 @@ #include "projectinfo.h" -#include +#include +#include +#include namespace CppTools { +ToolChainInfo::ToolChainInfo(const ProjectExplorer::ToolChain *toolChain, + const ProjectExplorer::Kit *kit) +{ + if (toolChain) { + // Keep the following cheap/non-blocking for the ui thread... + type = toolChain->typeId(); + isMsvc2015ToolChain + = toolChain->targetAbi().osFlavor() == ProjectExplorer::Abi::WindowsMsvc2015Flavor; + wordWidth = toolChain->targetAbi().wordWidth(); + targetTriple = type == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID + ? QLatin1String("i686-pc-windows-msvc") + : toolChain->originalTargetTriple(); // OK, compiler run is already cached. + + // ...and save the potentially expensive operations for later so that + // they can be run from a worker thread. + sysRoothPath = ProjectExplorer::SysRootKitInformation::sysRoot(kit).toString(); + headerPathsRunner = toolChain->createSystemHeaderPathsRunner(); + predefinedMacrosRunner = toolChain->createPredefinedMacrosRunner(); + } +} + +ProjectUpdateInfo::ProjectUpdateInfo(ProjectExplorer::Project *project, + const ProjectExplorer::ToolChain *cToolChain, + const ProjectExplorer::ToolChain *cxxToolChain, + const ProjectExplorer::Kit *kit, + const RawProjectParts &rawProjectParts) + : project(project) + , rawProjectParts(rawProjectParts) + , cToolChain(cToolChain) + , cxxToolChain(cxxToolChain) + , cToolChainInfo(ToolChainInfo(cToolChain, kit)) + , cxxToolChainInfo(ToolChainInfo(cxxToolChain, kit)) +{ +} + ProjectInfo::ProjectInfo(QPointer project) : m_project(project) { diff --git a/src/plugins/cpptools/projectinfo.h b/src/plugins/cpptools/projectinfo.h index 758775d4929..9096322989d 100644 --- a/src/plugins/cpptools/projectinfo.h +++ b/src/plugins/cpptools/projectinfo.h @@ -27,8 +27,12 @@ #include "cpptools_global.h" +#include "cpprawprojectpart.h" #include "projectpart.h" +#include +#include + #include #include #include @@ -36,6 +40,48 @@ namespace CppTools { +class ToolChainInfo +{ +public: + ToolChainInfo() = default; + ToolChainInfo(const ProjectExplorer::ToolChain *toolChain, + const ProjectExplorer::Kit *kit); + + bool isValid() const { return type.isValid(); } + +public: + Core::Id type; + bool isMsvc2015ToolChain = false; + unsigned wordWidth = 0; + QString targetTriple; + + QString sysRoothPath; // For headerPathsRunner. + ProjectExplorer::ToolChain::SystemHeaderPathsRunner headerPathsRunner; + ProjectExplorer::ToolChain::PredefinedMacrosRunner predefinedMacrosRunner; +}; + +class CPPTOOLS_EXPORT ProjectUpdateInfo +{ +public: + ProjectUpdateInfo() = default; + ProjectUpdateInfo(ProjectExplorer::Project *project, + const ProjectExplorer::ToolChain *cToolChain, + const ProjectExplorer::ToolChain *cxxToolChain, + const ProjectExplorer::Kit *kit, + const RawProjectParts &rawProjectParts); + bool isValid() const { return project && !rawProjectParts.isEmpty(); } + +public: + QPointer project; + QVector rawProjectParts; + + const ProjectExplorer::ToolChain *cToolChain = nullptr; + const ProjectExplorer::ToolChain *cxxToolChain = nullptr; + + ToolChainInfo cToolChainInfo; + ToolChainInfo cxxToolChainInfo; +}; + class CPPTOOLS_EXPORT ProjectInfo { public: diff --git a/src/plugins/cpptools/projectpartbuilder.cpp b/src/plugins/cpptools/projectpartbuilder.cpp deleted file mode 100644 index a2efe98b133..00000000000 --- a/src/plugins/cpptools/projectpartbuilder.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "projectpartbuilder.h" - -#include "projectinfo.h" - -#include -#include -#include -#include -#include -#include - -namespace CppTools { - -class ToolChainImpl : public ToolChainInterface -{ -public: - ToolChainImpl(ProjectExplorer::ToolChain &toolChain, - const ProjectExplorer::Kit *kit, - const QStringList &commandLineFlags) - : m_toolChain(toolChain) - , m_kit(kit) - , m_commandLineFlags(commandLineFlags) - { - } - - Core::Id type() const override - { - return m_toolChain.typeId(); - } - - bool isMsvc2015Toolchain() const override - { - return m_toolChain.targetAbi().osFlavor() == ProjectExplorer::Abi::WindowsMsvc2015Flavor; - } - - unsigned wordWidth() const override - { - return m_toolChain.targetAbi().wordWidth(); - } - - QString targetTriple() const override - { - if (type() == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) - return QLatin1String("i686-pc-windows-msvc"); - - return m_toolChain.originalTargetTriple(); - } - - QByteArray predefinedMacros() const override - { - return m_toolChain.predefinedMacros(m_commandLineFlags); - } - - QList systemHeaderPaths() const override - { - return m_toolChain.systemHeaderPaths( - m_commandLineFlags, - ProjectExplorer::SysRootKitInformation::sysRoot(m_kit)); - } - - ProjectExplorer::WarningFlags warningFlags() const override - { - return m_toolChain.warningFlags(m_commandLineFlags); - } - - ProjectExplorer::ToolChain::CompilerFlags compilerFlags() const override - { - return m_toolChain.compilerFlags(m_commandLineFlags); - } - -private: - ProjectExplorer::ToolChain &m_toolChain; - const ProjectExplorer::Kit *m_kit = nullptr; - const QStringList m_commandLineFlags; -}; - -class ProjectImpl : public ProjectInterface -{ -public: - ProjectImpl(ProjectExplorer::Project &project) - : m_project(project) - { - if (ProjectExplorer::Target *activeTarget = m_project.activeTarget()) - m_kit = activeTarget->kit(); - } - - QString displayName() const override - { - return m_project.displayName(); - } - - QString projectFilePath() const override - { - return m_project.projectFilePath().toString(); - } - - ToolChainInterfacePtr toolChain(Core::Id language, - const QStringList &commandLineFlags) const override - { - using namespace ProjectExplorer; - - if (ProjectExplorer::ToolChain *t = ToolChainKitInformation::toolChain(m_kit, language)) - return ToolChainInterfacePtr(new ToolChainImpl(*t, m_kit, commandLineFlags)); - - return ToolChainInterfacePtr(); - } - -private: - ProjectExplorer::Project &m_project; - ProjectExplorer::Kit *m_kit = nullptr; -}; - -ProjectPartBuilder::ProjectPartBuilder(ProjectInfo &projectInfo) - : BaseProjectPartBuilder(new ProjectImpl(*projectInfo.project().data()), projectInfo) -{ -} - -} // namespace CppTools diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index a06a6fba105..a6d3bff6a76 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include @@ -66,6 +66,7 @@ namespace Internal { //////////////////////////////////////////////////////////////////////////////////// GenericProject::GenericProject(Manager *manager, const QString &fileName) + : m_cppCodeModelUpdater(new CppTools::CppProjectUpdater(this)) { setId(Constants::GENERICPROJECT_ID); setProjectManager(manager); @@ -96,7 +97,7 @@ GenericProject::GenericProject(Manager *manager, const QString &fileName) GenericProject::~GenericProject() { - m_codeModelFuture.cancel(); + delete m_cppCodeModelUpdater; projectManager()->unregisterProject(this); } @@ -338,12 +339,19 @@ QStringList GenericProject::processEntries(const QStringList &paths, void GenericProject::refreshCppCodeModel() { - CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); + const Kit *k = nullptr; + if (Target *target = activeTarget()) + k = target->kit(); + else + k = KitManager::defaultKit(); + QTC_ASSERT(k, return); - m_codeModelFuture.cancel(); + ToolChain *cToolChain + = ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::C_LANGUAGE_ID); + ToolChain *cxxToolChain + = ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID); - CppTools::ProjectInfo pInfo(this); - CppTools::ProjectPartBuilder ppBuilder(pInfo); + m_cppCodeModelUpdater->cancel(); CppTools::ProjectPart::QtVersion activeQtVersion = CppTools::ProjectPart::NoQt; if (QtSupport::BaseQtVersion *qtVersion = @@ -354,16 +362,15 @@ void GenericProject::refreshCppCodeModel() activeQtVersion = CppTools::ProjectPart::Qt5; } - ppBuilder.setProjectFile(projectFilePath().toString()); - ppBuilder.setQtVersion(activeQtVersion); - ppBuilder.setIncludePaths(projectIncludePaths()); - ppBuilder.setConfigFileName(configFileName()); + CppTools::RawProjectPart rpp; + rpp.setProjectFile(projectFilePath().toString()); + rpp.setQtVersion(activeQtVersion); + rpp.setIncludePaths(projectIncludePaths()); + rpp.setConfigFileName(configFileName()); + rpp.setFiles(files()); - const QList languages = ppBuilder.createProjectPartsForFiles(files()); - for (Id language : languages) - setProjectLanguage(language, true); - - m_codeModelFuture = modelManager->updateProjectInfo(pInfo); + const CppTools::ProjectUpdateInfo projectInfoUpdate(this, cToolChain, cxxToolChain, k, {rpp}); + m_cppCodeModelUpdater->update(projectInfoUpdate); } void GenericProject::activeTargetWasChanged() diff --git a/src/plugins/genericprojectmanager/genericproject.h b/src/plugins/genericprojectmanager/genericproject.h index 59655c39cdf..815f8024b06 100644 --- a/src/plugins/genericprojectmanager/genericproject.h +++ b/src/plugins/genericprojectmanager/genericproject.h @@ -37,6 +37,8 @@ #include +namespace CppTools { class CppProjectUpdater; } + namespace GenericProjectManager { namespace Internal { @@ -104,7 +106,7 @@ private: QStringList m_rawProjectIncludePaths; QStringList m_projectIncludePaths; - QFuture m_codeModelFuture; + CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr; ProjectExplorer::Target *m_activeTarget = nullptr; }; diff --git a/src/plugins/nim/project/nimtoolchain.cpp b/src/plugins/nim/project/nimtoolchain.cpp index 2b26908267d..1c34ec24058 100644 --- a/src/plugins/nim/project/nimtoolchain.cpp +++ b/src/plugins/nim/project/nimtoolchain.cpp @@ -76,6 +76,11 @@ bool NimToolChain::isValid() const return fi.isExecutable(); } +ToolChain::PredefinedMacrosRunner NimToolChain::createPredefinedMacrosRunner() const +{ + return ToolChain::PredefinedMacrosRunner(); +} + QByteArray NimToolChain::predefinedMacros(const QStringList &) const { return QByteArray(); @@ -91,6 +96,11 @@ WarningFlags NimToolChain::warningFlags(const QStringList &) const return WarningFlags::NoWarnings; } +ToolChain::SystemHeaderPathsRunner NimToolChain::createSystemHeaderPathsRunner() const +{ + return ToolChain::SystemHeaderPathsRunner(); +} + QList NimToolChain::systemHeaderPaths(const QStringList &, const FileName &) const { return QList(); diff --git a/src/plugins/nim/project/nimtoolchain.h b/src/plugins/nim/project/nimtoolchain.h index 2bb59aac82d..7061a9751bc 100644 --- a/src/plugins/nim/project/nimtoolchain.h +++ b/src/plugins/nim/project/nimtoolchain.h @@ -40,10 +40,12 @@ public: ProjectExplorer::Abi targetAbi() const override; bool isValid() const override; + PredefinedMacrosRunner createPredefinedMacrosRunner() const override; QByteArray predefinedMacros(const QStringList &flags) const final; CompilerFlags compilerFlags(const QStringList &flags) const final; ProjectExplorer::WarningFlags warningFlags(const QStringList &flags) const final; + SystemHeaderPathsRunner createSystemHeaderPathsRunner() const override; QList systemHeaderPaths(const QStringList &flags, const Utils::FileName &sysRoot) const final; void addToEnvironment(Utils::Environment &env) const final; diff --git a/src/plugins/projectexplorer/abstractmsvctoolchain.cpp b/src/plugins/projectexplorer/abstractmsvctoolchain.cpp index 551a316bba4..c66be6cc4b2 100644 --- a/src/plugins/projectexplorer/abstractmsvctoolchain.cpp +++ b/src/plugins/projectexplorer/abstractmsvctoolchain.cpp @@ -47,7 +47,9 @@ namespace Internal { AbstractMsvcToolChain::AbstractMsvcToolChain(Core::Id typeId, Core::Id l, Detection d, const Abi &abi, const QString& vcvarsBat) : ToolChain(typeId, d), + m_predefinedMacrosMutex(new QMutex), m_lastEnvironment(Utils::Environment::systemEnvironment()), + m_headerPathsMutex(new QMutex), m_abi(abi), m_vcvarsBat(vcvarsBat) { @@ -63,6 +65,25 @@ AbstractMsvcToolChain::AbstractMsvcToolChain(Core::Id typeId, Detection d) : m_lastEnvironment(Utils::Environment::systemEnvironment()) { } +AbstractMsvcToolChain::~AbstractMsvcToolChain() +{ + delete m_predefinedMacrosMutex; + delete m_headerPathsMutex; +} + +AbstractMsvcToolChain::AbstractMsvcToolChain(const AbstractMsvcToolChain &other) + : ToolChain(other), + m_debuggerCommand(other.m_debuggerCommand), + m_predefinedMacrosMutex(new QMutex), + m_predefinedMacros(other.m_predefinedMacros), + m_lastEnvironment(other.m_lastEnvironment), + m_resultEnvironment(other.m_resultEnvironment), + m_headerPathsMutex(new QMutex), + m_abi(other.m_abi), + m_vcvarsBat(other.m_vcvarsBat) +{ +} + Abi AbstractMsvcToolChain::targetAbi() const { return m_abi; @@ -76,14 +97,23 @@ bool AbstractMsvcToolChain::isValid() const return fi.isFile() && fi.isExecutable(); } +ToolChain::PredefinedMacrosRunner AbstractMsvcToolChain::createPredefinedMacrosRunner() const +{ + Utils::Environment env(m_lastEnvironment); + addToEnvironment(env); + + // This runner must be thread-safe! + return [this, env](const QStringList &cxxflags) { + QMutexLocker locker(m_predefinedMacrosMutex); + if (m_predefinedMacros.isEmpty()) + m_predefinedMacros = msvcPredefinedMacros(cxxflags, env); + return m_predefinedMacros; + }; +} + QByteArray AbstractMsvcToolChain::predefinedMacros(const QStringList &cxxflags) const { - if (m_predefinedMacros.isEmpty()) { - Utils::Environment env(m_lastEnvironment); - addToEnvironment(env); - m_predefinedMacros = msvcPredefinedMacros(cxxflags, env); - } - return m_predefinedMacros; + return createPredefinedMacrosRunner()(cxxflags); } ToolChain::CompilerFlags AbstractMsvcToolChain::compilerFlags(const QStringList &cxxflags) const @@ -160,17 +190,25 @@ WarningFlags AbstractMsvcToolChain::warningFlags(const QStringList &cflags) cons return flags; } -QList AbstractMsvcToolChain::systemHeaderPaths(const QStringList &cxxflags, const Utils::FileName &sysRoot) const +ToolChain::SystemHeaderPathsRunner AbstractMsvcToolChain::createSystemHeaderPathsRunner() const { - Q_UNUSED(cxxflags); - Q_UNUSED(sysRoot); - if (m_headerPaths.isEmpty()) { - Utils::Environment env(m_lastEnvironment); - addToEnvironment(env); - foreach (const QString &path, env.value(QLatin1String("INCLUDE")).split(QLatin1Char(';'))) - m_headerPaths.append(HeaderPath(path, HeaderPath::GlobalHeaderPath)); - } - return m_headerPaths; + Utils::Environment env(m_lastEnvironment); + addToEnvironment(env); + + return [this, env](const QStringList &, const QString &) { + QMutexLocker locker(m_headerPathsMutex); + if (m_headerPaths.isEmpty()) { + foreach (const QString &path, env.value(QLatin1String("INCLUDE")).split(QLatin1Char(';'))) + m_headerPaths.append(HeaderPath(path, HeaderPath::GlobalHeaderPath)); + } + return m_headerPaths; + }; +} + +QList AbstractMsvcToolChain::systemHeaderPaths(const QStringList &cxxflags, + const Utils::FileName &sysRoot) const +{ + return createSystemHeaderPathsRunner()(cxxflags, sysRoot.toString()); } void AbstractMsvcToolChain::addToEnvironment(Utils::Environment &env) const @@ -231,6 +269,7 @@ bool AbstractMsvcToolChain::canClone() const return true; } +// Function must be thread-safe! QByteArray AbstractMsvcToolChain::msvcPredefinedMacros(const QStringList cxxflags, const Utils::Environment& env) const { diff --git a/src/plugins/projectexplorer/abstractmsvctoolchain.h b/src/plugins/projectexplorer/abstractmsvctoolchain.h index 653caed65b9..93556320df5 100644 --- a/src/plugins/projectexplorer/abstractmsvctoolchain.h +++ b/src/plugins/projectexplorer/abstractmsvctoolchain.h @@ -29,6 +29,8 @@ #include "abi.h" #include "headerpath.h" +#include + #include #include @@ -41,14 +43,18 @@ public: explicit AbstractMsvcToolChain(Core::Id typeId, Core::Id l, Detection d, const Abi &abi, const QString& vcvarsBat); explicit AbstractMsvcToolChain(Core::Id typeId, Detection d); + AbstractMsvcToolChain(const AbstractMsvcToolChain &other); + ~AbstractMsvcToolChain(); Abi targetAbi() const override; bool isValid() const override; + PredefinedMacrosRunner createPredefinedMacrosRunner() const override; QByteArray predefinedMacros(const QStringList &cxxflags) const override; CompilerFlags compilerFlags(const QStringList &cxxflags) const override; WarningFlags warningFlags(const QStringList &cflags) const override; + SystemHeaderPathsRunner createSystemHeaderPathsRunner() const override; QList systemHeaderPaths(const QStringList &cxxflags, const Utils::FileName &sysRoot) const override; void addToEnvironment(Utils::Environment &env) const override; @@ -89,9 +95,11 @@ protected: Utils::FileName m_debuggerCommand; + mutable QMutex *m_predefinedMacrosMutex = nullptr; mutable QByteArray m_predefinedMacros; mutable Utils::Environment m_lastEnvironment; // Last checked 'incoming' environment. mutable Utils::Environment m_resultEnvironment; // Resulting environment for VC + mutable QMutex *m_headerPathsMutex = nullptr; mutable QList m_headerPaths; Abi m_abi; diff --git a/src/plugins/projectexplorer/customtoolchain.cpp b/src/plugins/projectexplorer/customtoolchain.cpp index 3e86571f8fd..aaa545dfd1d 100644 --- a/src/plugins/projectexplorer/customtoolchain.cpp +++ b/src/plugins/projectexplorer/customtoolchain.cpp @@ -115,33 +115,43 @@ bool CustomToolChain::isValid() const return true; } -QByteArray CustomToolChain::predefinedMacros(const QStringList &cxxflags) const +ToolChain::PredefinedMacrosRunner CustomToolChain::createPredefinedMacrosRunner() const { - QByteArray result; - QStringList macros = m_predefinedMacros; - foreach (const QString &cxxFlag, cxxflags) { - if (cxxFlag.startsWith(QLatin1String("-D"))) { - macros << cxxFlag.mid(2).trimmed(); - } else if (cxxFlag.startsWith(QLatin1String("-U"))) { - const QString &removedName = cxxFlag.mid(2).trimmed(); - for (int i = macros.size() - 1; i >= 0; --i) { - const QString &m = macros.at(i); - if (m.left(m.indexOf(QLatin1Char('='))) == removedName) - macros.removeAt(i); + const QStringList theMacros = m_predefinedMacros; + + // This runner must be thread-safe! + return [theMacros](const QStringList &cxxflags){ + QByteArray result; + QStringList macros = theMacros; + foreach (const QString &cxxFlag, cxxflags) { + if (cxxFlag.startsWith(QLatin1String("-D"))) { + macros << cxxFlag.mid(2).trimmed(); + } else if (cxxFlag.startsWith(QLatin1String("-U"))) { + const QString &removedName = cxxFlag.mid(2).trimmed(); + for (int i = macros.size() - 1; i >= 0; --i) { + const QString &m = macros.at(i); + if (m.left(m.indexOf(QLatin1Char('='))) == removedName) + macros.removeAt(i); + } } } - } - foreach (const QString &str, macros) { - QByteArray ba = str.toUtf8(); - int equals = ba.indexOf('='); - if (equals == -1) { - result += "#define " + ba.trimmed() + '\n'; - } else { - result += "#define " + ba.left(equals).trimmed() + ' ' - + ba.mid(equals + 1).trimmed() + '\n'; + foreach (const QString &str, macros) { + QByteArray ba = str.toUtf8(); + int equals = ba.indexOf('='); + if (equals == -1) { + result += "#define " + ba.trimmed() + '\n'; + } else { + result += "#define " + ba.left(equals).trimmed() + ' ' + + ba.mid(equals + 1).trimmed() + '\n'; + } } - } - return result; + return result; + }; +} + +QByteArray CustomToolChain::predefinedMacros(const QStringList &cxxflags) const +{ + return createPredefinedMacrosRunner()(cxxflags); } ToolChain::CompilerFlags CustomToolChain::compilerFlags(const QStringList &cxxflags) const @@ -171,15 +181,26 @@ void CustomToolChain::setPredefinedMacros(const QStringList &list) toolChainUpdated(); } -QList CustomToolChain::systemHeaderPaths(const QStringList &cxxFlags, const FileName &) const +ToolChain::SystemHeaderPathsRunner CustomToolChain::createSystemHeaderPathsRunner() const { - QList flagHeaderPaths; - foreach (const QString &cxxFlag, cxxFlags) { - if (cxxFlag.startsWith(QLatin1String("-I"))) - flagHeaderPaths << HeaderPath(cxxFlag.mid(2).trimmed(), HeaderPath::GlobalHeaderPath); - } + const QList systemHeaderPaths = m_systemHeaderPaths; - return m_systemHeaderPaths + flagHeaderPaths; + // This runner must be thread-safe! + return [systemHeaderPaths](const QStringList &cxxFlags, const QString &) { + QList flagHeaderPaths; + foreach (const QString &cxxFlag, cxxFlags) { + if (cxxFlag.startsWith(QLatin1String("-I"))) + flagHeaderPaths << HeaderPath(cxxFlag.mid(2).trimmed(), HeaderPath::GlobalHeaderPath); + } + + return systemHeaderPaths + flagHeaderPaths; + }; +} + +QList CustomToolChain::systemHeaderPaths(const QStringList &cxxFlags, + const FileName &fileName) const +{ + return createSystemHeaderPathsRunner()(cxxFlags, fileName.toString()); } void CustomToolChain::addToEnvironment(Environment &env) const diff --git a/src/plugins/projectexplorer/customtoolchain.h b/src/plugins/projectexplorer/customtoolchain.h index de57c637f4a..a1dfe319bde 100644 --- a/src/plugins/projectexplorer/customtoolchain.h +++ b/src/plugins/projectexplorer/customtoolchain.h @@ -77,12 +77,14 @@ public: bool isValid() const override; + PredefinedMacrosRunner createPredefinedMacrosRunner() const override; QByteArray predefinedMacros(const QStringList &cxxflags) const override; CompilerFlags compilerFlags(const QStringList &cxxflags) const override; WarningFlags warningFlags(const QStringList &cxxflags) const override; const QStringList &rawPredefinedMacros() const; void setPredefinedMacros(const QStringList &list); + SystemHeaderPathsRunner createSystemHeaderPathsRunner() const override; QList systemHeaderPaths(const QStringList &cxxFlags, const Utils::FileName &) const override; void addToEnvironment(Utils::Environment &env) const override; diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index fa79ae5ce1c..da6cbeff2bc 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -66,6 +66,105 @@ static const char targetAbiKeyC[] = "ProjectExplorer.GccToolChain.TargetAbi"; static const char originalTargetTripleKeyC[] = "ProjectExplorer.GccToolChain.OriginalTargetTriple"; static const char supportedAbisKeyC[] = "ProjectExplorer.GccToolChain.SupportedAbis"; +static const int CACHE_SIZE = 16; + +HeaderPathsCache::HeaderPathsCache(const HeaderPathsCache &other) +{ + QMutexLocker locker(&m_mutex); + m_cache = other.cache(); +} + +void HeaderPathsCache::insert(const QStringList &compilerCommand, + const QList &headerPaths) +{ + CacheItem runResults; + runResults.first = compilerCommand; + runResults.second = headerPaths; + + QMutexLocker locker(&m_mutex); + bool cacheHit = false; + check(compilerCommand, &cacheHit); + if (!cacheHit) { + m_cache.push_back(runResults); + if (m_cache.size() > CACHE_SIZE) + m_cache.pop_front(); + } +} + +QList HeaderPathsCache::check(const QStringList &compilerCommand, + bool *cacheHit) const +{ + QMutexLocker locker(&m_mutex); + for (Cache::iterator it = m_cache.begin(); it != m_cache.end(); ++it) { + if (it->first == compilerCommand) { + // Increase cached item priority + CacheItem pair = *it; + m_cache.erase(it); + m_cache.push_back(pair); + + *cacheHit = true; + return pair.second; + } + } + + *cacheHit = false; + return QList(); +} + +HeaderPathsCache::Cache HeaderPathsCache::cache() const +{ + QMutexLocker locker(&m_mutex); + return m_cache; +} + +MacroCache::MacroCache(const MacroCache &other) +{ + QMutexLocker locker(&m_mutex); + m_cache = other.cache(); +} + +void MacroCache::insert(const QStringList &compilerCommand, const QByteArray ¯os) +{ + if (macros.isNull()) + return; + + CacheItem runResults; + QByteArray data = macros; + runResults.first = compilerCommand; + if (macros.isNull()) + data = QByteArray(""); + runResults.second = data; + + QMutexLocker locker(&m_mutex); + if (check(compilerCommand).isNull()) { + m_cache.push_back(runResults); + if (m_cache.size() > CACHE_SIZE) + m_cache.pop_front(); + } +} + +QByteArray MacroCache::check(const QStringList &compilerCommand) const +{ + QMutexLocker locker(&m_mutex); + for (Cache::iterator it = m_cache.begin(); it != m_cache.end(); ++it) { + if (it->first == compilerCommand) { + // Increase cached item priority + CacheItem pair = *it; + m_cache.erase(it); + m_cache.push_back(pair); + + return pair.second; + } + } + return QByteArray(); +} + +MacroCache::Cache MacroCache::cache() const +{ + QMutexLocker locker(&m_mutex); + return m_cache; +} + static QByteArray runGcc(const FileName &gcc, const QStringList &arguments, const QStringList &env) { if (gcc.isEmpty() || !gcc.toFileInfo().isExecutable()) @@ -115,8 +214,6 @@ static QByteArray gccPredefinedMacros(const FileName &gcc, const QStringList &ar return predefinedMacros; } -const int GccToolChain::PREDEFINED_MACROS_CACHE_SIZE = 16; - QList GccToolChain::gccHeaderPaths(const FileName &gcc, const QStringList &arguments, const QStringList &env) { @@ -252,38 +349,6 @@ void GccToolChain::setOriginalTargetTriple(const QString &targetTriple) toolChainUpdated(); } -void GccToolChain::setMacroCache(const QStringList &allCxxflags, const QByteArray ¯os) const -{ - if (macros.isNull()) - return; - - CacheItem runResults; - QByteArray data = macros; - runResults.first = allCxxflags; - if (macros.isNull()) - data = QByteArray(""); - runResults.second = data; - - m_predefinedMacros.push_back(runResults); - if (m_predefinedMacros.size() > PREDEFINED_MACROS_CACHE_SIZE) - m_predefinedMacros.pop_front(); -} - -QByteArray GccToolChain::macroCache(const QStringList &allCxxflags) const -{ - for (GccCache::iterator it = m_predefinedMacros.begin(); it != m_predefinedMacros.end(); ++it) { - if (it->first == allCxxflags) { - // Increase cached item priority - CacheItem pair = *it; - m_predefinedMacros.erase(it); - m_predefinedMacros.push_back(pair); - - return pair.second; - } - } - return QByteArray(); -} - QString GccToolChain::defaultDisplayName() const { if (!m_targetAbi.isValid()) @@ -348,6 +413,64 @@ bool GccToolChain::isValid() const return fi.isExecutable(); } +ToolChain::PredefinedMacrosRunner GccToolChain::createPredefinedMacrosRunner() const +{ + // Using a clean environment breaks ccache/distcc/etc. + Environment env = Environment::systemEnvironment(); + addToEnvironment(env); + const Utils::FileName compilerCommand = m_compilerCommand; + const QStringList platformCodeGenFlags = m_platformCodeGenFlags; + OptionsReinterpreter reinterpretOptions = m_optionsReinterpreter; + QTC_CHECK(reinterpretOptions); + MacroCache *macroCache = &m_predefinedMacrosCache; + + // This runner must be thread-safe! + return [env, compilerCommand, platformCodeGenFlags, reinterpretOptions, macroCache] + (const QStringList &cxxflags) { + QStringList allCxxflags = platformCodeGenFlags + cxxflags; // add only cxxflags is empty? + QStringList arguments = gccPredefinedMacrosOptions(); + for (int iArg = 0; iArg < allCxxflags.length(); ++iArg) { + const QString &a = allCxxflags.at(iArg); + if (a.startsWith("--gcc-toolchain=")) { + arguments << a; + } else if (a == "-arch") { + if (++iArg < allCxxflags.length() && !arguments.contains(a)) + arguments << a << allCxxflags.at(iArg); + } else if (a == "--sysroot" || a == "-isysroot" || a == "-D" ||a == "-U") { + if (++iArg < allCxxflags.length()) + arguments << a << allCxxflags.at(iArg); + } else if (a == "-m128bit-long-double" || a == "-m32" || a == "-m3dnow" || a == "-m3dnowa" + || a == "-m64" || a == "-m96bit-long-double" || a == "-mabm" || a == "-maes" + || a.startsWith("-march=") || a == "-mavx" || a.startsWith("-masm=") + || a == "-mcx16" || a == "-mfma" || a == "-mfma4" || a == "-mlwp" + || a == "-mpclmul" || a == "-mpopcnt" || a == "-msse" || a == "-msse2" + || a == "-msse2avx" || a == "-msse3" || a == "-msse4" || a == "-msse4.1" + || a == "-msse4.2" || a == "-msse4a" || a == "-mssse3" + || a.startsWith("-mtune=") || a == "-mxop" + || a == "-Os" || a == "-O0" || a == "-O1" || a == "-O2" || a == "-O3" + || a == "-ffinite-math-only" || a == "-fshort-double" || a == "-fshort-wchar" + || a == "-fsignaling-nans" || a == "-fno-inline" || a == "-fno-exceptions" + || a == "-fstack-protector" || a == "-fstack-protector-all" + || a == "-fsanitize=address" || a == "-fno-rtti" + || a.startsWith("-std=") || a.startsWith("-stdlib=") || a.startsWith("-specs=") + || a == "-ansi" || a == "-undef" || a.startsWith("-D") || a.startsWith("-U") + || a == "-fopenmp" || a == "-Wno-deprecated" || a == "-fPIC" || a == "-fpic" + || a == "-fPIE" || a == "-fpie") + arguments << a; + } + + arguments = reinterpretOptions(arguments); + QByteArray macros = macroCache->check(arguments); + if (!macros.isNull()) + return macros; + + macros = gccPredefinedMacros(compilerCommand, arguments, env.toStringList()); + macroCache->insert(arguments, macros); + + return macros; + }; +} + /** * @brief Asks compiler for set of predefined macros * @param cxxflags - compiler flags collected from project settings @@ -359,50 +482,7 @@ bool GccToolChain::isValid() const */ QByteArray GccToolChain::predefinedMacros(const QStringList &cxxflags) const { - QStringList allCxxflags = m_platformCodeGenFlags + cxxflags; // add only cxxflags is empty? - QStringList arguments = gccPredefinedMacrosOptions(); - for (int iArg = 0; iArg < allCxxflags.length(); ++iArg) { - const QString &a = allCxxflags.at(iArg); - if (a.startsWith("--gcc-toolchain=")) { - arguments << a; - } else if (a == "-arch") { - if (++iArg < allCxxflags.length() && !arguments.contains(a)) - arguments << a << allCxxflags.at(iArg); - } else if (a == "--sysroot" || a == "-isysroot" || a == "-D" ||a == "-U") { - if (++iArg < allCxxflags.length()) - arguments << a << allCxxflags.at(iArg); - } else if (a == "-m128bit-long-double" || a == "-m32" || a == "-m3dnow" || a == "-m3dnowa" - || a == "-m64" || a == "-m96bit-long-double" || a == "-mabm" || a == "-maes" - || a.startsWith("-march=") || a == "-mavx" || a.startsWith("-masm=") - || a == "-mcx16" || a == "-mfma" || a == "-mfma4" || a == "-mlwp" - || a == "-mpclmul" || a == "-mpopcnt" || a == "-msse" || a == "-msse2" - || a == "-msse2avx" || a == "-msse3" || a == "-msse4" || a == "-msse4.1" - || a == "-msse4.2" || a == "-msse4a" || a == "-mssse3" - || a.startsWith("-mtune=") || a == "-mxop" - || a == "-Os" || a == "-O0" || a == "-O1" || a == "-O2" || a == "-O3" - || a == "-ffinite-math-only" || a == "-fshort-double" || a == "-fshort-wchar" - || a == "-fsignaling-nans" || a == "-fno-inline" || a == "-fno-exceptions" - || a == "-fstack-protector" || a == "-fstack-protector-all" - || a == "-fsanitize=address" || a == "-fno-rtti" - || a.startsWith("-std=") || a.startsWith("-stdlib=") || a.startsWith("-specs=") - || a == "-ansi" || a == "-undef" || a.startsWith("-D") || a.startsWith("-U") - || a == "-fopenmp" || a == "-Wno-deprecated" || a == "-fPIC" || a == "-fpic" - || a == "-fPIE" || a == "-fpie") - arguments << a; - } - - QByteArray macros = macroCache(arguments); - if (!macros.isNull()) - return macros; - - // Using a clean environment breaks ccache/distcc/etc. - Environment env = Environment::systemEnvironment(); - addToEnvironment(env); - macros = gccPredefinedMacros(m_compilerCommand, reinterpretOptions(arguments), - env.toStringList()); - - setMacroCache(arguments, macros); - return macros; + return createPredefinedMacrosRunner()(cxxflags); } /** @@ -516,29 +596,52 @@ WarningFlags GccToolChain::warningFlags(const QStringList &cflags) const return flags; } -QList GccToolChain::systemHeaderPaths(const QStringList &cxxflags, const FileName &sysRoot) const +ToolChain::SystemHeaderPathsRunner GccToolChain::createSystemHeaderPathsRunner() const { - if (m_headerPaths.isEmpty()) { - // Using a clean environment breaks ccache/distcc/etc. - Environment env = Environment::systemEnvironment(); - addToEnvironment(env); + // Using a clean environment breaks ccache/distcc/etc. + Environment env = Environment::systemEnvironment(); + addToEnvironment(env); + + const Utils::FileName compilerCommand = m_compilerCommand; + const QStringList platformCodeGenFlags = m_platformCodeGenFlags; + OptionsReinterpreter reinterpretOptions = m_optionsReinterpreter; + QTC_CHECK(reinterpretOptions); + HeaderPathsCache *headerCache = &m_headerPathsCache; + + // This runner must be thread-safe! + return [env, compilerCommand, platformCodeGenFlags, reinterpretOptions, headerCache] + (const QStringList &cxxflags, const QString &sysRoot) { // Prepare arguments QStringList arguments; if (!sysRoot.isEmpty()) - arguments.append(QString::fromLatin1("--sysroot=%1").arg(sysRoot.toString())); + arguments.append(QString::fromLatin1("--sysroot=%1").arg(sysRoot)); QStringList flags; - flags << m_platformCodeGenFlags << cxxflags; + flags << platformCodeGenFlags << cxxflags; foreach (const QString &a, flags) { if (a.startsWith("-stdlib=") || a.startsWith("--gcctoolchain=")) arguments << a; } arguments << "-xc++" << "-E" << "-v" << "-"; + arguments = reinterpretOptions(arguments); - m_headerPaths = gccHeaderPaths(m_compilerCommand, reinterpretOptions(arguments), env.toStringList()); - } - return m_headerPaths; + bool cacheHit = false; + QList paths = headerCache->check(arguments, &cacheHit); + if (cacheHit) + return paths; + + paths = gccHeaderPaths(compilerCommand, arguments, env.toStringList()); + headerCache->insert(arguments, paths); + + return paths; + }; +} + +QList GccToolChain::systemHeaderPaths(const QStringList &cxxflags, + const FileName &sysRoot) const +{ + return createSystemHeaderPathsRunner()(cxxflags, sysRoot.toString()); } void GccToolChain::addCommandPathToEnvironment(const FileName &command, Environment &env) @@ -735,6 +838,11 @@ void GccToolChain::updateSupportedAbis() const } } +void GccToolChain::setOptionsReinterpreter(const OptionsReinterpreter &optionsReinterpreter) +{ + m_optionsReinterpreter = optionsReinterpreter; +} + GccToolChain::DetectedAbisResult GccToolChain::detectSupportedAbis() const { Environment env = Environment::systemEnvironment(); @@ -892,7 +1000,7 @@ QList GccToolChainFactory::autoDetectToolChain(const FileName &comp return result; tc->setLanguage(language); - tc->setMacroCache(QStringList(), macros); + tc->m_predefinedMacrosCache.insert(QStringList(), macros); tc->setCompilerCommand(compilerPath); tc->setSupportedAbis(detectedAbis.supportedAbis); tc->setTargetAbi(abi); @@ -957,7 +1065,7 @@ void GccToolChainConfigWidget::applyImpl() tc->setDisplayName(displayName); // reset display name tc->setPlatformCodeGenFlags(splitString(m_platformCodeGenFlagsLineEdit->text())); tc->setPlatformLinkerFlags(splitString(m_platformLinkerFlagsLineEdit->text())); - tc->setMacroCache(tc->platformCodeGenFlags(), m_macros); + tc->m_predefinedMacrosCache.insert(tc->platformCodeGenFlags(), m_macros); } void GccToolChainConfigWidget::setFromToolchain() diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h index 2d7bfc70cad..be2ef37b246 100644 --- a/src/plugins/projectexplorer/gcctoolchain.h +++ b/src/plugins/projectexplorer/gcctoolchain.h @@ -32,8 +32,11 @@ #include "headerpath.h" #include +#include #include +#include + namespace ProjectExplorer { namespace Internal { @@ -48,6 +51,42 @@ class LinuxIccToolChainFactory; // GccToolChain // -------------------------------------------------------------------------- +class PROJECTEXPLORER_EXPORT HeaderPathsCache +{ +public: + HeaderPathsCache() : m_mutex(QMutex::Recursive) {} + HeaderPathsCache(const HeaderPathsCache &other); + void insert(const QStringList &compilerCommand, const QList &headerPaths); + QList check(const QStringList &compilerCommand, bool *cacheHit) const; + +protected: + using CacheItem = QPair>; + using Cache = QList; + Cache cache() const; + +private: + mutable QMutex m_mutex; + mutable Cache m_cache; +}; + +class PROJECTEXPLORER_EXPORT MacroCache +{ +public: + MacroCache() : m_mutex(QMutex::Recursive) {} + MacroCache(const MacroCache &other); + void insert(const QStringList &compilerCommand, const QByteArray ¯os); + QByteArray check(const QStringList &compilerCommand) const; + +protected: + using CacheItem = QPair; + using Cache = QList; + Cache cache() const; + +private: + mutable QMutex m_mutex; + mutable Cache m_cache; +}; + class PROJECTEXPLORER_EXPORT GccToolChain : public ToolChain { public: @@ -61,12 +100,16 @@ public: bool isValid() const override; - QByteArray predefinedMacros(const QStringList &cxxflags) const override; CompilerFlags compilerFlags(const QStringList &cxxflags) const override; WarningFlags warningFlags(const QStringList &cflags) const override; + PredefinedMacrosRunner createPredefinedMacrosRunner() const override; + QByteArray predefinedMacros(const QStringList &cxxflags) const override; + + SystemHeaderPathsRunner createSystemHeaderPathsRunner() const override; QList systemHeaderPaths(const QStringList &cxxflags, const Utils::FileName &sysRoot) const override; + void addToEnvironment(Utils::Environment &env) const override; QString makeCommand(const Utils::Environment &environment) const override; Utils::FileNameList suggestedMkspecList() const override; @@ -104,16 +147,13 @@ public: }; protected: - typedef QList > GccCache; - GccToolChain(const GccToolChain &) = default; - typedef QPair CacheItem; - void setCompilerCommand(const Utils::FileName &path); void setSupportedAbis(const QList &m_abis); void setOriginalTargetTriple(const QString &targetTriple); - void setMacroCache(const QStringList &allCxxflags, const QByteArray ¯oCache) const; + + void setMacroCache(const QStringList &allCxxflags, const QByteArray ¯os) const; QByteArray macroCache(const QStringList &allCxxflags) const; virtual QString defaultDisplayName() const; @@ -124,12 +164,10 @@ protected: // Reinterpret options for compiler drivers inheriting from GccToolChain (e.g qcc) to apply -Wp option // that passes the initial options directly down to the gcc compiler - virtual QStringList reinterpretOptions(const QStringList &argument) const { return argument; } + using OptionsReinterpreter = std::function; + void setOptionsReinterpreter(const OptionsReinterpreter &optionsReinterpreter); static QList gccHeaderPaths(const Utils::FileName &gcc, const QStringList &args, const QStringList &env); - static const int PREDEFINED_MACROS_CACHE_SIZE; - mutable GccCache m_predefinedMacros; - class WarningFlagAdder { public: @@ -153,12 +191,17 @@ private: QStringList m_platformCodeGenFlags; QStringList m_platformLinkerFlags; + OptionsReinterpreter m_optionsReinterpreter = [](const QStringList &v) { return v; }; + Abi m_targetAbi; mutable QList m_supportedAbis; mutable QString m_originalTargetTriple; mutable QList m_headerPaths; mutable QString m_version; + mutable MacroCache m_predefinedMacrosCache; + mutable HeaderPathsCache m_headerPathsCache; + friend class Internal::GccToolChainConfigWidget; friend class Internal::GccToolChainFactory; friend class ToolChainFactory; diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 3d5d3410193..3306d896ac4 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -287,6 +287,7 @@ static QByteArray msvcCompilationFile() } // Run MSVC 'cl' compiler to obtain #defines. +// Function must be thread-safe! QByteArray MsvcToolChain::msvcPredefinedMacros(const QStringList cxxflags, const Utils::Environment &env) const { diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h index f77a1637fee..e7973800c3a 100644 --- a/src/plugins/projectexplorer/msvctoolchain.h +++ b/src/plugins/projectexplorer/msvctoolchain.h @@ -81,6 +81,7 @@ protected: explicit MsvcToolChain(Core::Id typeId); Utils::Environment readEnvironmentSetting(const Utils::Environment& env) const final; + // Function must be thread-safe! QByteArray msvcPredefinedMacros(const QStringList cxxflags, const Utils::Environment &env) const override; diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h index 49004f37d09..abc6f115580 100644 --- a/src/plugins/projectexplorer/toolchain.h +++ b/src/plugins/projectexplorer/toolchain.h @@ -37,6 +37,8 @@ #include #include +#include + namespace Utils { class Environment; } namespace ProjectExplorer { @@ -99,8 +101,6 @@ public: virtual bool isValid() const = 0; - virtual QByteArray predefinedMacros(const QStringList &cxxflags) const = 0; - enum CompilerFlag { NoFlags = 0, StandardCxx11 = 0x1, @@ -118,8 +118,16 @@ public: Q_DECLARE_FLAGS(CompilerFlags, CompilerFlag) virtual CompilerFlags compilerFlags(const QStringList &cxxflags) const = 0; - virtual WarningFlags warningFlags(const QStringList &cflags) const = 0; + + // A PredefinedMacrosRunner is created in the ui thread and runs in another thread. + using PredefinedMacrosRunner = std::function; + virtual PredefinedMacrosRunner createPredefinedMacrosRunner() const = 0; + virtual QByteArray predefinedMacros(const QStringList &cxxflags) const = 0; + + // A SystemHeaderPathsRunner is created in the ui thread and runs in another thread. + using SystemHeaderPathsRunner = std::function(const QStringList &cxxflags, const QString &sysRoot)>; + virtual SystemHeaderPathsRunner createSystemHeaderPathsRunner() const = 0; virtual QList systemHeaderPaths(const QStringList &cxxflags, const Utils::FileName &sysRoot) const = 0; virtual void addToEnvironment(Utils::Environment &env) const = 0; diff --git a/src/plugins/projectexplorer/toolchainmanager.cpp b/src/plugins/projectexplorer/toolchainmanager.cpp index fd8c2ea2315..f1ae19fe411 100644 --- a/src/plugins/projectexplorer/toolchainmanager.cpp +++ b/src/plugins/projectexplorer/toolchainmanager.cpp @@ -491,9 +491,11 @@ public: QString typeDisplayName() const override { return QLatin1String("Test Tool Chain"); } Abi targetAbi() const override { return Abi::hostAbi(); } bool isValid() const override { return m_valid; } + PredefinedMacrosRunner createPredefinedMacrosRunner() const override { return PredefinedMacrosRunner(); } QByteArray predefinedMacros(const QStringList &cxxflags) const override { Q_UNUSED(cxxflags); return QByteArray(); } CompilerFlags compilerFlags(const QStringList &cxxflags) const override { Q_UNUSED(cxxflags); return NoFlags; } WarningFlags warningFlags(const QStringList &cflags) const override { Q_UNUSED(cflags); return WarningFlags::NoWarnings; } + SystemHeaderPathsRunner createSystemHeaderPathsRunner() const override { return SystemHeaderPathsRunner(); } QList systemHeaderPaths(const QStringList &cxxflags, const FileName &sysRoot) const override { Q_UNUSED(cxxflags); Q_UNUSED(sysRoot); return QList(); } void addToEnvironment(Environment &env) const override { Q_UNUSED(env); } diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 0ccd2d731e4..438c40f2336 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include @@ -123,6 +123,7 @@ QbsProject::QbsProject(QbsManager *manager, const QString &fileName) : m_qbsUpdateFutureInterface(0), m_parsingScheduled(false), m_cancelStatus(CancelStatusNone), + m_cppCodeModelUpdater(new CppTools::CppProjectUpdater(this)), m_currentBc(0), m_extraCompilersPending(false) { @@ -143,11 +144,16 @@ QbsProject::QbsProject(QbsManager *manager, const QString &fileName) : connect(this, &Project::environmentChanged, this, &QbsProject::delayParsing); connect(&m_parsingDelay, &QTimer::timeout, this, &QbsProject::startParsing); + + connect(m_cppCodeModelUpdater, &CppTools::CppProjectUpdater::projectInfoUpdated, this, + [this](const CppTools::ProjectInfo &projectInfo){ + m_cppCodeModelProjectInfo = projectInfo; + }); } QbsProject::~QbsProject() { - m_codeModelFuture.cancel(); + delete m_cppCodeModelUpdater; delete m_qbsProjectParser; if (m_qbsUpdateFutureInterface) { m_qbsUpdateFutureInterface->reportCanceled(); @@ -895,20 +901,27 @@ void QbsProject::updateCppCodeModel() if (!m_projectData.isValid()) return; + const Kit *k = nullptr; + if (Target *target = activeTarget()) + k = target->kit(); + else + k = KitManager::defaultKit(); + QTC_ASSERT(k, return); + + ToolChain *cToolChain + = ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::C_LANGUAGE_ID); + ToolChain *cxxToolChain + = ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID); + QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(activeTarget()->kit()); - CppTools::CppModelManager *modelmanager = CppTools::CppModelManager::instance(); - CppTools::ProjectInfo pinfo(this); - CppTools::ProjectPartBuilder ppBuilder(pinfo); - + CppTools::ProjectPart::QtVersion qtVersionForPart = CppTools::ProjectPart::NoQt; if (qtVersion) { if (qtVersion->qtVersion() < QtSupport::QtVersionNumber(5,0,0)) - ppBuilder.setQtVersion(CppTools::ProjectPart::Qt4); + qtVersionForPart = CppTools::ProjectPart::Qt4; else - ppBuilder.setQtVersion(CppTools::ProjectPart::Qt5); - } else { - ppBuilder.setQtVersion(CppTools::ProjectPart::NoQt); + qtVersionForPart = CppTools::ProjectPart::Qt5; } QList factories = @@ -918,6 +931,8 @@ void QbsProject::updateCppCodeModel() qDeleteAll(m_extraCompilers); m_extraCompilers.clear(); + + CppTools::RawProjectParts rpps; foreach (const qbs::ProductData &prd, m_projectData.allProducts()) { QString cPch; QString cxxPch; @@ -941,13 +956,16 @@ void QbsProject::updateCppCodeModel() } foreach (const qbs::GroupData &grp, prd.groups()) { + CppTools::RawProjectPart rpp; + // TODO: Set the Qt version only if this particular product depends on Qt. + rpp.setQtVersion(qtVersionForPart); const qbs::PropertyMap &props = grp.properties(); QStringList cFlags; QStringList cxxFlags; getExpandedCompilerFlags(cFlags, cxxFlags, props); - ppBuilder.setCxxFlags(cxxFlags); - ppBuilder.setCFlags(cFlags); + rpp.setFlagsForC({cToolChain, cFlags}); + rpp.setFlagsForCxx({cxxToolChain, cxxFlags}); QStringList list = props.getModulePropertiesAsStringList( QLatin1String(CONFIG_CPP_MODULE), @@ -962,7 +980,7 @@ void QbsProject::updateCppCodeModel() data.append(" 1"); // cpp.defines: [ "FOO" ] is considered to be "FOO=1" grpDefines += (QByteArray("#define ") + data + '\n'); } - ppBuilder.setDefines(grpDefines); + rpp.setDefines(grpDefines); list = props.getModulePropertiesAsStringList(QLatin1String(CONFIG_CPP_MODULE), QLatin1String(CONFIG_INCLUDEPATHS)); @@ -985,10 +1003,10 @@ void QbsProject::updateCppCodeModel() FileName::fromUserInput(p).toString(), CppTools::ProjectPartHeaderPath::FrameworkPath); - ppBuilder.setHeaderPaths(grpHeaderPaths); + rpp.setHeaderPaths(grpHeaderPaths); - ppBuilder.setDisplayName(grp.name()); - ppBuilder.setProjectFile(groupLocationToProjectFile(grp.location())); + rpp.setDisplayName(grp.name()); + rpp.setProjectFile(groupLocationToProjectFile(grp.location())); QHash filePathToSourceArtifact; bool hasCFiles = false; @@ -1051,33 +1069,26 @@ void QbsProject::updateCppCodeModel() << grp.name() << "in product" << prd.name(); qCWarning(qbsPmLog) << "Expect problems with code model"; } - ppBuilder.setPreCompiledHeaders(pchFiles); - - const QList languages = ppBuilder.createProjectPartsForFiles( - grp.allFilePaths(), - [filePathToSourceArtifact](const QString &filePath) { - return cppFileType(filePathToSourceArtifact.value(filePath)); + rpp.setPreCompiledHeaders(pchFiles); + rpp.setFiles(grp.allFilePaths(), [filePathToSourceArtifact](const QString &filePath) { + // Keep this lambda thread-safe! + return cppFileType(filePathToSourceArtifact.value(filePath)); }); - foreach (Id language, languages) - setProjectLanguage(language, true); + rpps.append(rpp); + } } CppTools::GeneratedCodeModelSupport::update(m_extraCompilers); - - // Update the code model - m_codeModelFuture.cancel(); - m_codeModelFuture = modelmanager->updateProjectInfo(pinfo); - m_codeModelProjectInfo = modelmanager->projectInfo(this); - QTC_CHECK(m_codeModelProjectInfo.isValid()); + m_cppCodeModelUpdater->update({this, cToolChain, cxxToolChain, k, rpps}); } void QbsProject::updateCppCompilerCallData() { OpTimer optimer("updateCppCompilerCallData"); CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); - QTC_ASSERT(m_codeModelProjectInfo == modelManager->projectInfo(this), return); + QTC_ASSERT(m_cppCodeModelProjectInfo == modelManager->projectInfo(this), return); CppTools::ProjectInfo::CompilerCallData data; foreach (const qbs::ProductData &product, m_projectData.allProducts()) { @@ -1117,7 +1128,7 @@ void QbsProject::updateCppCompilerCallData() } } - m_codeModelProjectInfo = modelManager->updateCompilerCallDataForProject(this, data); + m_cppCodeModelProjectInfo = modelManager->updateCompilerCallDataForProject(this, data); } void QbsProject::updateQmlJsCodeModel() diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h index 079212075da..c28f403ff3b 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.h +++ b/src/plugins/qbsprojectmanager/qbsproject.h @@ -45,6 +45,7 @@ #include namespace Core { class IDocument; } +namespace CppTools { class CppProjectUpdater; } namespace ProjectExplorer { class BuildConfiguration; } namespace QbsProjectManager { @@ -164,8 +165,8 @@ private: CancelStatusCancelingAltoghether } m_cancelStatus; - QFuture m_codeModelFuture; - CppTools::ProjectInfo m_codeModelProjectInfo; + CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr; + CppTools::ProjectInfo m_cppCodeModelProjectInfo; QbsBuildConfiguration *m_currentBc; diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 10fa5ce8144..3a6c2f25b0e 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -39,10 +39,10 @@ #include #include #include -#include +#include #include -#include #include +#include #include #include #include @@ -247,7 +247,8 @@ bool QmakeProjectFile::reload(QString *errorString, ReloadFlag flag, ChangeType QmakeProject::QmakeProject(QmakeManager *manager, const QString &fileName) : m_projectFiles(new QmakeProjectFiles), - m_qmakeVfs(new QMakeVfs) + m_qmakeVfs(new QMakeVfs), + m_cppCodeModelUpdater(new CppTools::CppProjectUpdater(this)) { setId(Constants::QMAKEPROJECT_ID); setProjectManager(manager); @@ -275,7 +276,8 @@ QmakeProject::~QmakeProject() { delete m_projectImporter; m_projectImporter = nullptr; - m_codeModelFuture.cancel(); + delete m_cppCodeModelUpdater; + m_cppCodeModelUpdater = nullptr; m_asyncUpdateState = ShuttingDown; // Make sure root node (and associated readers) are shut hown before proceeding @@ -352,6 +354,13 @@ void QmakeProject::updateCppCodeModel() k = KitManager::defaultKit(); QTC_ASSERT(k, return); + ToolChain *cToolChain + = ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::C_LANGUAGE_ID); + ToolChain *cxxToolChain + = ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID); + + m_cppCodeModelUpdater->cancel(); + QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(k); ProjectPart::QtVersion qtVersionForPart = ProjectPart::NoQt; if (qtVersion) { @@ -363,26 +372,26 @@ void QmakeProject::updateCppCodeModel() FindQmakeProFiles findQmakeProFiles; const QList proFiles = findQmakeProFiles(rootProjectNode()); - CppTools::ProjectInfo projectInfo(this); - CppTools::ProjectPartBuilder ppBuilder(projectInfo); QList generators; - + CppTools::RawProjectParts rpps; foreach (QmakeProFileNode *pro, proFiles) { warnOnToolChainMismatch(pro); - ppBuilder.setDisplayName(pro->displayName()); - ppBuilder.setProjectFile(pro->filePath().toString()); - ppBuilder.setCxxFlags(pro->variableValue(Variable::CppFlags)); // TODO: Handle QMAKE_CFLAGS - ppBuilder.setDefines(pro->cxxDefines()); - ppBuilder.setPreCompiledHeaders(pro->variableValue(Variable::PrecompiledHeader)); - ppBuilder.setSelectedForBuilding(pro->includedInExactParse()); + CppTools::RawProjectPart rpp; + rpp.setDisplayName(pro->displayName()); + rpp.setProjectFile(pro->filePath().toString()); + // TODO: Handle QMAKE_CFLAGS + rpp.setFlagsForCxx({cxxToolChain, pro->variableValue(Variable::CppFlags)}); + rpp.setDefines(pro->cxxDefines()); + rpp.setPreCompiledHeaders(pro->variableValue(Variable::PrecompiledHeader)); + rpp.setSelectedForBuilding(pro->includedInExactParse()); // Qt Version if (pro->variableValue(Variable::Config).contains(QLatin1String("qt"))) - ppBuilder.setQtVersion(qtVersionForPart); + rpp.setQtVersion(qtVersionForPart); else - ppBuilder.setQtVersion(ProjectPart::NoQt); + rpp.setQtVersion(ProjectPart::NoQt); // Header paths CppTools::ProjectPartHeaderPaths headerPaths; @@ -397,7 +406,7 @@ void QmakeProject::updateCppCodeModel() headerPaths += CppToolsHeaderPath(qtVersion->frameworkInstallPath(), CppToolsHeaderPath::FrameworkPath); } - ppBuilder.setHeaderPaths(headerPaths); + rpp.setHeaderPaths(headerPaths); // Files and generators QStringList fileList = pro->variableValue(Variable::Source); @@ -408,14 +417,13 @@ void QmakeProject::updateCppCodeModel() }); } generators.append(proGenerators); + rpp.setFiles(fileList); - const QList languages = ppBuilder.createProjectPartsForFiles(fileList); - foreach (const Core::Id &language, languages) - setProjectLanguage(language, true); + rpps.append(rpp); } CppTools::GeneratedCodeModelSupport::update(generators); - m_codeModelFuture = CppTools::CppModelManager::instance()->updateProjectInfo(projectInfo); + m_cppCodeModelUpdater->update({this, cToolChain, cxxToolChain, k, rpps}); } void QmakeProject::updateQmlJSCodeModel() @@ -523,7 +531,7 @@ void QmakeProject::scheduleAsyncUpdate(QmakeProFileNode *node, QmakeProFile::Asy m_partialEvaluate.append(node); // Cancel running code model update - m_codeModelFuture.cancel(); + m_cppCodeModelUpdater->cancel(); startAsyncTimer(delay); } else if (m_asyncUpdateState == AsyncUpdateInProgress) { @@ -561,7 +569,7 @@ void QmakeProject::scheduleAsyncUpdate(QmakeProFile::AsyncUpdateDelay delay) m_asyncUpdateState = AsyncFullUpdatePending; // Cancel running code model update - m_codeModelFuture.cancel(); + m_cppCodeModelUpdater->cancel(); startAsyncTimer(delay); } diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.h b/src/plugins/qmakeprojectmanager/qmakeproject.h index fb8ddfdbf68..eec07a2f9fd 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.h +++ b/src/plugins/qmakeprojectmanager/qmakeproject.h @@ -42,6 +42,7 @@ class QMakeGlobals; class QMakeVfs; QT_END_NAMESPACE +namespace CppTools { class CppProjectUpdater; } namespace ProjectExplorer { class DeploymentData; } namespace QtSupport { class ProFileReader; } @@ -205,7 +206,7 @@ private: bool m_cancelEvaluate = false; QList m_partialEvaluate; - QFuture m_codeModelFuture; + CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr; Internal::CentralizedFolderWatcher *m_centralizedFolderWatcher = nullptr; diff --git a/src/plugins/qnx/qnxtoolchain.cpp b/src/plugins/qnx/qnxtoolchain.cpp index f2b158167c1..65ce094fb0f 100644 --- a/src/plugins/qnx/qnxtoolchain.cpp +++ b/src/plugins/qnx/qnxtoolchain.cpp @@ -81,9 +81,29 @@ static void setQnxEnvironment(Environment &env, const QList &qn } } +// Qcc is a multi-compiler driver, and most of the gcc options can be accomplished by using the -Wp, and -Wc +// options to pass the options directly down to the compiler +static QStringList reinterpretOptions(const QStringList &args) +{ + QStringList arguments; + foreach (const QString &str, args) { + if (str.startsWith(QLatin1String("--sysroot="))) + continue; + QString arg = str; + if (arg == QLatin1String("-v") + || arg == QLatin1String("-dM")) + arg.prepend(QLatin1String("-Wp,")); + arguments << arg; + } + + return arguments; +} + QnxToolChain::QnxToolChain(ToolChain::Detection d) : GccToolChain(Constants::QNX_TOOLCHAIN_ID, d) -{ } +{ + setOptionsReinterpreter(&reinterpretOptions); +} QnxToolChain::QnxToolChain(Core::Id l, ToolChain::Detection d) : QnxToolChain(d) @@ -156,24 +176,6 @@ GccToolChain::DetectedAbisResult QnxToolChain::detectSupportedAbis() const return detectTargetAbis(FileName::fromString(m_sdpPath)); } -// Qcc is a multi-compiler driver, and most of the gcc options can be accomplished by using the -Wp, and -Wc -// options to pass the options directly down to the compiler -QStringList QnxToolChain::reinterpretOptions(const QStringList &args) const -{ - QStringList arguments; - foreach (const QString &str, args) { - if (str.startsWith(QLatin1String("--sysroot="))) - continue; - QString arg = str; - if (arg == QLatin1String("-v") - || arg == QLatin1String("-dM")) - arg.prepend(QLatin1String("-Wp,")); - arguments << arg; - } - - return arguments; -} - // -------------------------------------------------------------------------- // QnxToolChainFactory // -------------------------------------------------------------------------- diff --git a/src/plugins/qnx/qnxtoolchain.h b/src/plugins/qnx/qnxtoolchain.h index e20c9f66ead..93f2c15bc60 100644 --- a/src/plugins/qnx/qnxtoolchain.h +++ b/src/plugins/qnx/qnxtoolchain.h @@ -53,8 +53,6 @@ public: protected: virtual DetectedAbisResult detectSupportedAbis() const override; - QStringList reinterpretOptions(const QStringList &args) const override; - private: QString m_sdpPath; }; diff --git a/src/plugins/cpptools/projectpartbuilder.h b/tests/unit/mockup/projectexplorer/kitinformation.h similarity index 79% rename from src/plugins/cpptools/projectpartbuilder.h rename to tests/unit/mockup/projectexplorer/kitinformation.h index 22f5a47b5d4..fced31a50f2 100644 --- a/src/plugins/cpptools/projectpartbuilder.h +++ b/tests/unit/mockup/projectexplorer/kitinformation.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -25,18 +25,16 @@ #pragma once -#include "cpptools_global.h" +#include -#include "cppbaseprojectpartbuilder.h" +namespace ProjectExplorer { -namespace CppTools { +class Kit; -class ProjectInfo; - -class CPPTOOLS_EXPORT ProjectPartBuilder : public BaseProjectPartBuilder +class SysRootKitInformation { public: - ProjectPartBuilder(ProjectInfo &projectInfo); + static Utils::FileName sysRoot(const Kit *) { return Utils::FileName(); } }; -} // namespace CppTools +} // namespace ProjectExplorer diff --git a/tests/unit/mockup/projectexplorer/toolchain.h b/tests/unit/mockup/projectexplorer/toolchain.h new file mode 100644 index 00000000000..33bfa836dff --- /dev/null +++ b/tests/unit/mockup/projectexplorer/toolchain.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include +#include + +#include + +namespace ProjectExplorer { + +class ToolChain +{ +public: + Core::Id typeId() const { return Core::Id(); } + + enum CompilerFlag { + NoFlags = 0, + StandardCxx11 = 0x1, + StandardC99 = 0x2, + StandardC11 = 0x4, + GnuExtensions = 0x8, + MicrosoftExtensions = 0x10, + BorlandExtensions = 0x20, + OpenMP = 0x40, + ObjectiveC = 0x80, + StandardCxx14 = 0x100, + StandardCxx17 = 0x200, + StandardCxx98 = 0x400, + }; + Q_DECLARE_FLAGS(CompilerFlags, CompilerFlag) + + Abi targetAbi() const { return Abi(); } + + using SystemHeaderPathsRunner = std::function(const QStringList &cxxflags, const QString &sysRoot)>; + virtual SystemHeaderPathsRunner createSystemHeaderPathsRunner() const { return SystemHeaderPathsRunner(); } + + using PredefinedMacrosRunner = std::function; + virtual PredefinedMacrosRunner createPredefinedMacrosRunner() const { return PredefinedMacrosRunner(); } + + virtual QString originalTargetTriple() const { return QString(); } +}; + +} // namespace ProjectExplorer diff --git a/tests/unit/unittest/cppbaseprojectpartbuilder-test.cpp b/tests/unit/unittest/cppbaseprojectpartbuilder-test.cpp deleted file mode 100644 index cb2108658d6..00000000000 --- a/tests/unit/unittest/cppbaseprojectpartbuilder-test.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "googletest.h" -#include "gtest-qt-printing.h" -#include "mimedatabase-utilities.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include - -using CppTools::BaseProjectPartBuilder; -using CppTools::ProjectFile; -using CppTools::ProjectFiles; -using CppTools::ProjectInfo; -using CppTools::ProjectInterface; -using CppTools::ProjectPart; -using CppTools::ToolChainInterface; -using CppTools::ToolChainInterfacePtr; - -using testing::Contains; -using testing::Eq; -using testing::UnorderedElementsAre; -using testing::PrintToString; - -namespace { - -MATCHER_P2(IsProjectPart, languageVersion, fileKind, - std::string(negation ? "isn't" : "is") - + " project part with language version " + PrintToString(languageVersion) - + " and file kind " + PrintToString(fileKind)) -{ - const ProjectPart::Ptr &projectPart = arg; - - return projectPart->languageVersion == languageVersion - && projectPart->files.at(0).kind == fileKind; -} - -class EditableToolChain : public CppTools::ToolChainInterface -{ -public: - void setCompilerFlags(ProjectExplorer::ToolChain::CompilerFlags compilerFlags) - { - m_compilerFlags = compilerFlags; - } - -private: - Core::Id type() const override { return Core::Id(); } - bool isMsvc2015Toolchain() const override { return false; } - unsigned wordWidth() const override { return 64; } - QString targetTriple() const override { return QString(); } - - QByteArray predefinedMacros() const override { return QByteArray(); } - QList systemHeaderPaths() const override - { return QList(); } - - ProjectExplorer::WarningFlags warningFlags() const override - { return ProjectExplorer::WarningFlags(); } - - ProjectExplorer::ToolChain::CompilerFlags compilerFlags() const override - { return m_compilerFlags; } - -private: - ProjectExplorer::ToolChain::CompilerFlags m_compilerFlags; -}; - -class EditableProject : public CppTools::ProjectInterface -{ -public: - void setToolChain(ToolChainInterface *toolChain) - { - m_toolChain = toolChain; - } - -private: - QString displayName() const override { return QString(); } - QString projectFilePath() const override { return QString(); } - - ToolChainInterfacePtr toolChain(Core::Id, - const QStringList &) const override - { return ToolChainInterfacePtr(m_toolChain); } - -private: - CppTools::ToolChainInterface *m_toolChain = nullptr; -}; - -class BaseProjectPartBuilder : public ::testing::Test -{ -protected: - void SetUp() override; - - QObject dummyProjectExplorerProject; - ProjectInfo projectInfo{static_cast(&dummyProjectExplorerProject)}; -}; - -TEST_F(BaseProjectPartBuilder, CreateNoPartsForEmptyFileList) -{ - ::BaseProjectPartBuilder builder(new EditableProject, projectInfo); - - builder.createProjectPartsForFiles(QStringList()); - - ASSERT_TRUE(projectInfo.projectParts().isEmpty()); -} - -TEST_F(BaseProjectPartBuilder, CreateSinglePart) -{ - ::BaseProjectPartBuilder builder(new EditableProject, projectInfo); - - builder.createProjectPartsForFiles(QStringList() << "foo.cpp" << "foo.h"); - - ASSERT_THAT(projectInfo.projectParts().size(), Eq(1)); -} - -TEST_F(BaseProjectPartBuilder, CreateMultipleParts) -{ - ::BaseProjectPartBuilder builder(new EditableProject, projectInfo); - - builder.createProjectPartsForFiles(QStringList() << "foo.cpp" << "foo.h" - << "bar.c" << "bar.h"); - - ASSERT_THAT(projectInfo.projectParts().size(), Eq(2)); -} - -TEST_F(BaseProjectPartBuilder, ProjectPartIndicatesObjectiveCExtensionsByDefault) -{ - ::BaseProjectPartBuilder builder(new EditableProject, projectInfo); - - builder.createProjectPartsForFiles(QStringList() << "foo.mm"); - - ASSERT_THAT(projectInfo.projectParts().size(), Eq(1)); - const ProjectPart &projectPart = *projectInfo.projectParts().at(0); - ASSERT_TRUE(projectPart.languageExtensions & ProjectPart::ObjectiveCExtensions); -} - -TEST_F(BaseProjectPartBuilder, ProjectPartHasLatestLanguageVersionByDefault) -{ - ::BaseProjectPartBuilder builder(new EditableProject, projectInfo); - - builder.createProjectPartsForFiles(QStringList() << "foo.cpp"); - - ASSERT_THAT(projectInfo.projectParts().size(), Eq(1)); - const ProjectPart &projectPart = *projectInfo.projectParts().at(0); - ASSERT_THAT(projectPart.languageVersion, Eq(ProjectPart::LatestCxxVersion)); -} - -TEST_F(BaseProjectPartBuilder, ToolChainSetsLanguageVersion) -{ - auto toolChain = new EditableToolChain; - toolChain->setCompilerFlags(ProjectExplorer::ToolChain::StandardCxx98); - auto project = new EditableProject; - project->setToolChain(toolChain); - ::BaseProjectPartBuilder builder(project, projectInfo); - - builder.createProjectPartsForFiles(QStringList() << "foo.cpp"); - - ASSERT_THAT(projectInfo.projectParts().size(), Eq(1)); - const ProjectPart &projectPart = *projectInfo.projectParts().at(0); - ASSERT_THAT(projectPart.languageVersion, Eq(ProjectPart::CXX98)); -} - -TEST_F(BaseProjectPartBuilder, ToolChainSetsLanguageExtensions) -{ - auto toolChain = new EditableToolChain; - toolChain->setCompilerFlags(ProjectExplorer::ToolChain::MicrosoftExtensions); - auto project = new EditableProject; - project->setToolChain(toolChain); - ::BaseProjectPartBuilder builder(project, projectInfo); - - builder.createProjectPartsForFiles(QStringList() << "foo.cpp"); - - ASSERT_THAT(projectInfo.projectParts().size(), Eq(1)); - const ProjectPart &projectPart = *projectInfo.projectParts().at(0); - ASSERT_TRUE(projectPart.languageExtensions & ProjectPart::MicrosoftExtensions); -} - -TEST_F(BaseProjectPartBuilder, ProjectFileKindsMatchProjectPartVersion) -{ - ::BaseProjectPartBuilder builder(new EditableProject, projectInfo); - - builder.createProjectPartsForFiles(QStringList() << "foo.h"); - - ASSERT_THAT(projectInfo.projectParts(), - UnorderedElementsAre(IsProjectPart(ProjectPart::LatestCVersion, ProjectFile::CHeader), - IsProjectPart(ProjectPart::LatestCVersion, ProjectFile::ObjCHeader), - IsProjectPart(ProjectPart::LatestCxxVersion, ProjectFile::CXXHeader), - IsProjectPart(ProjectPart::LatestCxxVersion, ProjectFile::ObjCXXHeader))); -} - -TEST_F(BaseProjectPartBuilder, ReportsCxxLanguage) -{ - ::BaseProjectPartBuilder builder(new EditableProject, projectInfo); - - const QList languages = builder.createProjectPartsForFiles(QStringList() << "foo.cpp"); - - ASSERT_THAT(languages, Eq(QList() << ProjectExplorer::Constants::CXX_LANGUAGE_ID)); -} - -TEST_F(BaseProjectPartBuilder, ReportsCLanguage) -{ - ::BaseProjectPartBuilder builder(new EditableProject, projectInfo); - - const QList languages = builder.createProjectPartsForFiles(QStringList() << "foo.c"); - - ASSERT_THAT(languages, Eq(QList() << ProjectExplorer::Constants::C_LANGUAGE_ID)); -} - -void BaseProjectPartBuilder::SetUp() -{ - ASSERT_TRUE(MimeDataBaseUtilities::addCppToolsMimeTypes()); -} - -} // anonymous namespace diff --git a/tests/unit/unittest/cppprojectinfogenerator-test.cpp b/tests/unit/unittest/cppprojectinfogenerator-test.cpp new file mode 100644 index 00000000000..9a991a75204 --- /dev/null +++ b/tests/unit/unittest/cppprojectinfogenerator-test.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "googletest.h" +#include "gtest-qt-printing.h" +#include "mimedatabase-utilities.h" + +#include +#include + +#include + +using CppTools::Internal::ProjectInfoGenerator; +using CppTools::ProjectFile; +using CppTools::ProjectInfo; +using CppTools::ProjectUpdateInfo; +using CppTools::ProjectPart; +using CppTools::RawProjectPart; + +using ProjectExplorer::ToolChain; + +using testing::Eq; +using testing::UnorderedElementsAre; +using testing::PrintToString; + +namespace { + +MATCHER_P2(IsProjectPart, languageVersion, fileKind, + std::string(negation ? "isn't" : "is") + + " project part with language version " + PrintToString(languageVersion) + + " and file kind " + PrintToString(fileKind)) +{ + const ProjectPart::Ptr &projectPart = arg; + + return projectPart->languageVersion == languageVersion + && projectPart->files.at(0).kind == fileKind; +} + +class ProjectInfoGenerator : public ::testing::Test +{ +protected: + void SetUp() override; + ProjectInfo generate(); + +protected: + RawProjectPart rawProjectPart; +}; + +TEST_F(ProjectInfoGenerator, CreateNoProjectPartsForEmptyFileList) +{ + const ProjectInfo projectInfo = generate(); + + ASSERT_TRUE(projectInfo.projectParts().isEmpty()); +} + +TEST_F(ProjectInfoGenerator, CreateSingleProjectPart) +{ + rawProjectPart.files = QStringList{ "foo.cpp", "foo.h"}; + + const ProjectInfo projectInfo = generate(); + + ASSERT_THAT(projectInfo.projectParts().size(), Eq(1)); +} + +TEST_F(ProjectInfoGenerator, CreateMultipleProjectParts) +{ + rawProjectPart.files = QStringList{ "foo.cpp", "foo.h", "bar.c", "bar.h" }; + + const ProjectInfo projectInfo = generate(); + + ASSERT_THAT(projectInfo.projectParts().size(), Eq(2)); +} + +TEST_F(ProjectInfoGenerator, ProjectPartIndicatesObjectiveCExtensionsByDefault) +{ + rawProjectPart.files = QStringList{ "foo.mm" }; + + const ProjectInfo projectInfo = generate(); + + ASSERT_THAT(projectInfo.projectParts().size(), Eq(1)); + const ProjectPart &projectPart = *projectInfo.projectParts().at(0); + ASSERT_TRUE(projectPart.languageExtensions & ProjectPart::ObjectiveCExtensions); +} + +TEST_F(ProjectInfoGenerator, ProjectPartHasLatestLanguageVersionByDefault) +{ + rawProjectPart.files = QStringList{ "foo.cpp" }; + + const ProjectInfo projectInfo = generate(); + + ASSERT_THAT(projectInfo.projectParts().size(), Eq(1)); + const ProjectPart &projectPart = *projectInfo.projectParts().at(0); + ASSERT_THAT(projectPart.languageVersion, Eq(ProjectPart::LatestCxxVersion)); +} + +TEST_F(ProjectInfoGenerator, UseCompilerFlagsForLanguageVersion) +{ + rawProjectPart.files = QStringList{ "foo.cpp" }; + rawProjectPart.flagsForCxx.compilerFlags = ToolChain::CompilerFlag::StandardCxx98; + + const ProjectInfo projectInfo = generate(); + + ASSERT_THAT(projectInfo.projectParts().size(), Eq(1)); + const ProjectPart &projectPart = *projectInfo.projectParts().at(0); + ASSERT_THAT(projectPart.languageVersion, Eq(ProjectPart::CXX98)); +} + +TEST_F(ProjectInfoGenerator, UseCompilerFlagsForLangaugeExtensions) +{ + rawProjectPart.files = QStringList{ "foo.cpp" }; + rawProjectPart.flagsForCxx.compilerFlags = ToolChain::CompilerFlag::MicrosoftExtensions; + + const ProjectInfo projectInfo = generate(); + + ASSERT_THAT(projectInfo.projectParts().size(), Eq(1)); + const ProjectPart &projectPart = *projectInfo.projectParts().at(0); + ASSERT_TRUE(projectPart.languageExtensions & ProjectPart::MicrosoftExtensions); +} + +TEST_F(ProjectInfoGenerator, ProjectFileKindsMatchProjectPartVersion) +{ + rawProjectPart.files = QStringList{ "foo.h" }; + + const ProjectInfo projectInfo = generate(); + + ASSERT_THAT(projectInfo.projectParts(), + UnorderedElementsAre(IsProjectPart(ProjectPart::LatestCVersion, ProjectFile::CHeader), + IsProjectPart(ProjectPart::LatestCVersion, ProjectFile::ObjCHeader), + IsProjectPart(ProjectPart::LatestCxxVersion, ProjectFile::CXXHeader), + IsProjectPart(ProjectPart::LatestCxxVersion, ProjectFile::ObjCXXHeader))); +} + +void ProjectInfoGenerator::SetUp() +{ + ASSERT_TRUE(MimeDataBaseUtilities::addCppToolsMimeTypes()); +} + +ProjectInfo ProjectInfoGenerator::generate() +{ + QFutureInterface fi; + ProjectUpdateInfo projectUpdateInfo; + projectUpdateInfo.rawProjectParts += rawProjectPart; + ::ProjectInfoGenerator generator(fi, projectUpdateInfo); + + return generator.generate(); +} + +} // anonymous namespace diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 390f54fe937..133f762c266 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -32,7 +32,7 @@ SOURCES += \ clientserverinprocess-test.cpp \ lineprefixer-test.cpp \ cppprojectfilecategorizer-test.cpp \ - cppbaseprojectpartbuilder-test.cpp \ + cppprojectinfogenerator-test.cpp \ cppprojectpartchooser-test.cpp \ processevents-utilities.cpp \ mimedatabase-utilities.cpp \