summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Bubke <marco.bubke@qt.io>2017-02-07 15:00:38 +0100
committerMarco Bubke <marco.bubke@qt.io>2017-09-14 15:23:56 +0000
commitb6e12f4a1c2a8dbc7a672f0cf42ea76ece71b10d (patch)
tree81550e7fce5053ecb1ead60ddf59534d44517a87
parent3adb71d45ebebd8c8fc2ec6beeb7a5ee67d64e4e (diff)
downloadqt-creator-b6e12f4a1c2a8dbc7a672f0cf42ea76ece71b10d.tar.gz
Convert macros from plain QByteArray to a vector of structs
The old code model expected the macros as C++ formatted text ("#define Foo 42) but newer targets like the Clang codemodel expect key value arguments like "-DFoo=42". So instead of parsing the text again and again we use an abstract data description. Task-number: QTCREATORBUG-17915 Change-Id: I0179fd13c48a581e91ee79bba9d42d501c26f19f Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
-rw-r--r--src/plugins/autotest/qtest/qttestparser.cpp2
-rw-r--r--src/plugins/autotest/quick/quicktestparser.cpp25
-rw-r--r--src/plugins/autotoolsprojectmanager/autotoolsproject.cpp2
-rw-r--r--src/plugins/autotoolsprojectmanager/makefileparser.cpp10
-rw-r--r--src/plugins/autotoolsprojectmanager/makefileparser.h9
-rw-r--r--src/plugins/autotoolsprojectmanager/makefileparserthread.cpp6
-rw-r--r--src/plugins/autotoolsprojectmanager/makefileparserthread.h11
-rw-r--r--src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp27
-rw-r--r--src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp4
-rw-r--r--src/plugins/cmakeprojectmanager/cmakecbpparser.cpp18
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeproject.cpp2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeproject.h3
-rw-r--r--src/plugins/cmakeprojectmanager/servermodereader.cpp22
-rw-r--r--src/plugins/cmakeprojectmanager/servermodereader.h2
-rw-r--r--src/plugins/cmakeprojectmanager/tealeafreader.cpp2
-rw-r--r--src/plugins/cppeditor/cppcodemodelinspectordialog.cpp36
-rw-r--r--src/plugins/cpptools/builtineditordocumentparser.cpp5
-rw-r--r--src/plugins/cpptools/compileroptionsbuilder.cpp102
-rw-r--r--src/plugins/cpptools/compileroptionsbuilder.h10
-rw-r--r--src/plugins/cpptools/cppcodemodelinspectordumper.cpp11
-rw-r--r--src/plugins/cpptools/cppcompletionassist.cpp2
-rw-r--r--src/plugins/cpptools/cppfindreferences.cpp15
-rw-r--r--src/plugins/cpptools/cppmodelmanager.cpp48
-rw-r--r--src/plugins/cpptools/cppmodelmanager.h4
-rw-r--r--src/plugins/cpptools/cppmodelmanager_test.cpp18
-rw-r--r--src/plugins/cpptools/cppprojectinfogenerator.cpp4
-rw-r--r--src/plugins/cpptools/cpprawprojectpart.cpp4
-rw-r--r--src/plugins/cpptools/cpprawprojectpart.h4
-rw-r--r--src/plugins/cpptools/cppsourceprocessor.cpp21
-rw-r--r--src/plugins/cpptools/cpptoolsunittestfiles.pri4
-rw-r--r--src/plugins/cpptools/projectinfo.cpp11
-rw-r--r--src/plugins/cpptools/projectinfo.h2
-rw-r--r--src/plugins/cpptools/projectpart.cpp15
-rw-r--r--src/plugins/cpptools/projectpart.h5
-rw-r--r--src/plugins/nim/project/nimtoolchain.cpp4
-rw-r--r--src/plugins/nim/project/nimtoolchain.h2
-rw-r--r--src/plugins/projectexplorer/abstractmsvctoolchain.cpp9
-rw-r--r--src/plugins/projectexplorer/abstractmsvctoolchain.h9
-rw-r--r--src/plugins/projectexplorer/customtoolchain.cpp63
-rw-r--r--src/plugins/projectexplorer/customtoolchain.h8
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.cpp109
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.h28
-rw-r--r--src/plugins/projectexplorer/gcctoolchainfactories.h2
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.cpp41
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.h4
-rw-r--r--src/plugins/projectexplorer/projectexplorer.pro6
-rw-r--r--src/plugins/projectexplorer/projectexplorerunittestfiles.pri12
-rw-r--r--src/plugins/projectexplorer/projectmacro.cpp219
-rw-r--r--src/plugins/projectexplorer/projectmacro.h102
-rw-r--r--src/plugins/projectexplorer/toolchain.h5
-rw-r--r--src/plugins/projectexplorer/toolchainmanager.cpp2
-rw-r--r--src/plugins/qbsprojectmanager/qbsproject.cpp12
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeproject.cpp2
-rw-r--r--tests/unit/mockup/projectexplorer/toolchain.h3
-rw-r--r--tests/unit/unittest/creator_dependency.pri2
-rw-r--r--tests/unit/unittest/google-using-declarations.h1
-rw-r--r--tests/unit/unittest/gtest-creator-printing.cpp34
-rw-r--r--tests/unit/unittest/gtest-creator-printing.h10
-rw-r--r--tests/unit/unittest/projectmacro-test.cpp408
-rw-r--r--tests/unit/unittest/unittest.pro3
60 files changed, 1145 insertions, 421 deletions
diff --git a/src/plugins/autotest/qtest/qttestparser.cpp b/src/plugins/autotest/qtest/qttestparser.cpp
index 93376cba7c..476422295d 100644
--- a/src/plugins/autotest/qtest/qttestparser.cpp
+++ b/src/plugins/autotest/qtest/qttestparser.cpp
@@ -86,7 +86,7 @@ static bool qtTestLibDefined(const QString &fileName)
const QList<CppTools::ProjectPart::Ptr> parts =
CppTools::CppModelManager::instance()->projectPart(fileName);
if (parts.size() > 0)
- return parts.at(0)->projectDefines.contains("#define QT_TESTLIB_LIB");
+ return parts.at(0)->projectMacros.contains({"QT_TESTLIB_LIB"});
return false;
}
diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp
index 0d897fe04e..46566952ff 100644
--- a/src/plugins/autotest/quick/quicktestparser.cpp
+++ b/src/plugins/autotest/quick/quicktestparser.cpp
@@ -89,20 +89,21 @@ static bool includesQtQuickTest(const CPlusPlus::Document::Ptr &doc,
static QString quickTestSrcDir(const CppTools::CppModelManager *cppMM,
const QString &fileName)
{
- static const QByteArray qtsd(" QUICK_TEST_SOURCE_DIR ");
const QList<CppTools::ProjectPart::Ptr> parts = cppMM->projectPart(fileName);
if (parts.size() > 0) {
- QByteArray projDefines(parts.at(0)->projectDefines);
- for (const QByteArray &line : projDefines.split('\n')) {
- if (line.contains(qtsd)) {
- QByteArray result = line.mid(line.indexOf(qtsd) + qtsd.length());
- if (result.startsWith('"'))
- result.remove(result.length() - 1, 1).remove(0, 1);
- if (result.startsWith("\\\""))
- result.remove(result.length() - 2, 2).remove(0, 2);
- return QLatin1String(result);
- }
- }
+ const ProjectExplorer::Macros &macros = parts.at(0)->projectMacros;
+ auto found = std::find_if(
+ macros.begin(),
+ macros.end(),
+ [] (const ProjectExplorer::Macro &macro) { return macro.key == "QUICK_TEST_SOURCE_DIR"; });
+ if (found != macros.end()) {
+ QByteArray result = found->value;
+ if (result.startsWith('"'))
+ result.remove(result.length() - 1, 1).remove(0, 1);
+ if (result.startsWith("\\\""))
+ result.remove(result.length() - 2, 2).remove(0, 2);
+ return QLatin1String(result);
+ }
}
return QString();
}
diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
index a24993187e..01105d8497 100644
--- a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
+++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
@@ -298,7 +298,7 @@ void AutotoolsProject::updateCppCodeModel()
? target->activeBuildConfiguration()->buildDirectory().toString() : QString();
rpp.setIncludePaths(filterIncludes(absSrc, absBuild, m_makefileParserThread->includePaths()));
- rpp.setDefines(m_makefileParserThread->defines());
+ rpp.setMacros(m_makefileParserThread->macros());
rpp.setFiles(m_files);
m_cppCodeModelUpdater->update({this, cToolChain, cxxToolChain, k, {rpp}});
diff --git a/src/plugins/autotoolsprojectmanager/makefileparser.cpp b/src/plugins/autotoolsprojectmanager/makefileparser.cpp
index 74e29054ec..9c3e32216b 100644
--- a/src/plugins/autotoolsprojectmanager/makefileparser.cpp
+++ b/src/plugins/autotoolsprojectmanager/makefileparser.cpp
@@ -108,9 +108,9 @@ QStringList MakefileParser::includePaths() const
return m_includePaths;
}
-QByteArray MakefileParser::defines() const
+ProjectExplorer::Macros MakefileParser::macros() const
{
- return m_defines;
+ return m_macros;
}
QStringList MakefileParser::cflags() const
@@ -449,11 +449,7 @@ bool MakefileParser::maybeParseDefine(const QString &term)
{
if (term.startsWith(QLatin1String("-D"))) {
QString def = term.mid(2); // remove the "-D"
- QByteArray data = def.toUtf8();
- int pos = data.indexOf('=');
- if (pos >= 0)
- data[pos] = ' ';
- m_defines += (QByteArray("#define ") + data + '\n');
+ m_macros += ProjectExplorer::Macro::fromKeyValue(def);
return true;
}
return false;
diff --git a/src/plugins/autotoolsprojectmanager/makefileparser.h b/src/plugins/autotoolsprojectmanager/makefileparser.h
index beaa1a57db..d6387bc29c 100644
--- a/src/plugins/autotoolsprojectmanager/makefileparser.h
+++ b/src/plugins/autotoolsprojectmanager/makefileparser.h
@@ -27,10 +27,13 @@
#pragma once
+#include <projectexplorer/projectmacro.h>
+
#include <QMutex>
#include <QStringList>
#include <QTextStream>
#include <QObject>
+#include <QVector>
QT_FORWARD_DECLARE_CLASS(QDir)
@@ -49,6 +52,8 @@ class MakefileParser : public QObject
{
Q_OBJECT
+ using Macros = ProjectExplorer::Macros;
+
public:
/**
* @param makefile Filename including path of the autotools
@@ -98,7 +103,7 @@ public:
* #define X12_HAS_DEPRECATED
* @endcode
*/
- QByteArray defines() const;
+ Macros macros() const;
/**
* @return List of compiler flags for C.
@@ -267,7 +272,7 @@ private:
QStringList m_sources; ///< Return value for MakefileParser::sources()
QStringList m_makefiles; ///< Return value for MakefileParser::makefiles()
QStringList m_includePaths; ///< Return value for MakefileParser::includePaths()
- QByteArray m_defines; ///< Return value for MakefileParser::defines()
+ Macros m_macros; ///< Return value for MakefileParser::macros()
QStringList m_cflags; ///< Return value for MakefileParser::cflags()
QStringList m_cxxflags; ///< Return value for MakefileParser::cxxflags()
QStringList m_cppflags; ///< The cpp flags, which will be part of both cflags and cxxflags
diff --git a/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp b/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp
index cfe7e9757f..a33d39599b 100644
--- a/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp
+++ b/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp
@@ -61,10 +61,10 @@ QStringList MakefileParserThread::includePaths() const
return m_includePaths;
}
-QByteArray MakefileParserThread::defines() const
+ProjectExplorer::Macros MakefileParserThread::macros() const
{
QMutexLocker locker(&m_mutex);
- return m_defines;
+ return m_macros;
}
QStringList MakefileParserThread::cflags() const
@@ -109,7 +109,7 @@ void MakefileParserThread::run()
m_sources = m_parser.sources();
m_makefiles = m_parser.makefiles();
m_includePaths = m_parser.includePaths();
- m_defines = m_parser.defines();
+ m_macros = m_parser.macros();
m_cflags = m_parser.cflags();
m_cxxflags = m_parser.cxxflags();
}
diff --git a/src/plugins/autotoolsprojectmanager/makefileparserthread.h b/src/plugins/autotoolsprojectmanager/makefileparserthread.h
index 94b965d133..3e16bdccc4 100644
--- a/src/plugins/autotoolsprojectmanager/makefileparserthread.h
+++ b/src/plugins/autotoolsprojectmanager/makefileparserthread.h
@@ -29,9 +29,12 @@
#include "makefileparser.h"
+#include <projectexplorer/projectmacro.h>
+
#include <QMutex>
#include <QStringList>
#include <QThread>
+#include <QVector>
namespace AutotoolsProjectManager {
namespace Internal {
@@ -47,6 +50,8 @@ class MakefileParserThread : public QThread
{
Q_OBJECT
+ using Macros = ProjectExplorer::Macros;
+
public:
MakefileParserThread(const QString &makefile);
@@ -82,10 +87,10 @@ public:
QStringList includePaths() const;
/**
- * @return Concatenated defines. Should be invoked, after the signal
+ * @return Concatenated macros. Should be invoked, after the signal
* finished() has been emitted.
*/
- QByteArray defines() const;
+ Macros macros() const;
/**
* @return List of compiler flags for C. Should be invoked, after the signal
@@ -134,7 +139,7 @@ private:
QStringList m_sources; ///< Return value for MakefileParserThread::sources()
QStringList m_makefiles; ///< Return value for MakefileParserThread::makefiles()
QStringList m_includePaths; ///< Return value for MakefileParserThread::includePaths()
- QByteArray m_defines; ///< Return value for MakefileParserThread::defines()
+ Macros m_macros; ///< Return value for MakefileParserThread::macros()
QStringList m_cflags; ///< Return value for MakefileParserThread::cflags()
QStringList m_cxxflags; ///< Return value for MakefileParserThread::cxxflags()
};
diff --git a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp
index db09aea672..8a9736a15a 100644
--- a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp
+++ b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp
@@ -512,7 +512,7 @@ bool OpenEditorAtCursorPosition::waitUntil(const std::function<bool ()> &conditi
}
CppTools::ProjectPart::Ptr createProjectPart(const QStringList &files,
- const QString &defines)
+ const ProjectExplorer::Macros &macros)
{
using namespace CppTools;
@@ -521,19 +521,19 @@ CppTools::ProjectPart::Ptr createProjectPart(const QStringList &files,
foreach (const QString &file, files)
projectPart->files.append(ProjectFile(file, ProjectFile::classify(file)));
projectPart->qtVersion = ProjectPart::NoQt;
- projectPart->projectDefines = defines.toUtf8();
+ projectPart->projectMacros = macros;
return projectPart;
}
CppTools::ProjectInfo createProjectInfo(ProjectExplorer::Project *project,
const QStringList &files,
- const QString &defines)
+ const ProjectExplorer::Macros &macros)
{
using namespace CppTools;
QTC_ASSERT(project, return ProjectInfo());
- const CppTools::ProjectPart::Ptr projectPart = createProjectPart(files, defines);
+ const CppTools::ProjectPart::Ptr projectPart = createProjectPart(files, macros);
ProjectInfo projectInfo = ProjectInfo(project);
projectInfo.appendProjectPart(projectPart);
return projectInfo;
@@ -543,11 +543,11 @@ class ProjectLoader
{
public:
ProjectLoader(const QStringList &projectFiles,
- const QString &projectDefines,
+ const ProjectExplorer::Macros &projectMacros,
bool testOnlyForCleanedProjects = false)
: m_project(0)
, m_projectFiles(projectFiles)
- , m_projectDefines(projectDefines)
+ , m_projectMacros(projectMacros)
, m_helper(0, testOnlyForCleanedProjects)
{
}
@@ -557,17 +557,17 @@ public:
m_project = m_helper.createProject(QLatin1String("testProject"));
const CppTools::ProjectInfo projectInfo = createProjectInfo(m_project,
m_projectFiles,
- m_projectDefines);
+ m_projectMacros);
const QSet<QString> filesIndexedAfterLoading = m_helper.updateProjectInfo(projectInfo);
return m_projectFiles.size() == filesIndexedAfterLoading.size();
}
- bool updateProject(const QString &updatedProjectDefines)
+ bool updateProject(const ProjectExplorer::Macros &updatedProjectMacros)
{
QTC_ASSERT(m_project, return false);
const CppTools::ProjectInfo updatedProjectInfo = createProjectInfo(m_project,
m_projectFiles,
- updatedProjectDefines);
+ updatedProjectMacros);
return updateProjectInfo(updatedProjectInfo);
}
@@ -581,7 +581,7 @@ private:
ProjectExplorer::Project *m_project;
QStringList m_projectFiles;
- QString m_projectDefines;
+ ProjectExplorer::Macros m_projectMacros;
CppTools::Tests::ModelManagerTestHelper m_helper;
};
@@ -865,8 +865,7 @@ void ClangCodeCompletionTest::testCompleteProjectDependingCode()
const TestDocument testDocument("completionWithProject.cpp");
QVERIFY(testDocument.isCreatedAndHasValidCursorPosition());
- ProjectLoader projectLoader(QStringList(testDocument.filePath),
- _("#define PROJECT_CONFIGURATION_1\n"));
+ ProjectLoader projectLoader(QStringList(testDocument.filePath), {{"PROJECT_CONFIGURATION_1"}});
QVERIFY(projectLoader.load());
OpenEditorAtCursorPosition openEditor(testDocument);
@@ -891,7 +890,7 @@ void ClangCodeCompletionTest::testCompleteProjectDependingCodeAfterChangingProje
{
// Check completion with project configuration 1
ProjectLoader projectLoader(QStringList(testDocument.filePath),
- _("#define PROJECT_CONFIGURATION_1\n"),
+ {{"PROJECT_CONFIGURATION_1"}},
/* testOnlyForCleanedProjects= */ true);
QVERIFY(projectLoader.load());
openEditor.waitUntilProjectPartChanged(QLatin1String("myproject.project"));
@@ -902,7 +901,7 @@ void ClangCodeCompletionTest::testCompleteProjectDependingCodeAfterChangingProje
QVERIFY(!hasItem(proposal, "projectConfiguration2"));
// Check completion with project configuration 2
- QVERIFY(projectLoader.updateProject(_("#define PROJECT_CONFIGURATION_2\n")));
+ QVERIFY(projectLoader.updateProject({{"PROJECT_CONFIGURATION_2"}}));
proposal = completionResults(openEditor.editor());
QVERIFY(!hasItem(proposal, "projectConfiguration1"));
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp
index ad6363bc0e..0cfafa08e1 100644
--- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp
@@ -224,8 +224,8 @@ public:
optionsBuilder.addDefineToAvoidIncludingGccOrMinGwIntrinsics();
const Core::Id type = projectPart.toolchainType;
if (type != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
- optionsBuilder.addDefines(projectPart.toolchainDefines);
- optionsBuilder.addDefines(projectPart.projectDefines);
+ optionsBuilder.addMacros(projectPart.toolChainMacros);
+ optionsBuilder.addMacros(projectPart.projectMacros);
optionsBuilder.undefineClangVersionMacrosForMsvc();
optionsBuilder.undefineCppLanguageFeatureMacrosForMsvc2015();
optionsBuilder.addHeaderPathOptions();
diff --git a/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp b/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp
index 591768f515..96cf7d138d 100644
--- a/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp
@@ -30,6 +30,7 @@
#include <utils/fileutils.h>
#include <utils/stringutils.h>
#include <utils/algorithm.h>
+#include <projectexplorer/projectmacro.h>
#include <projectexplorer/projectnodes.h>
#include <QLoggingCategory>
@@ -71,8 +72,9 @@ void CMakeCbpParser::sortFiles()
qCDebug(log) << "# Pre Dump #";
qCDebug(log) << "###############";
foreach (const CMakeBuildTarget &target, m_buildTargets)
- qCDebug(log) << target.title << target.sourceDirectory <<
- target.includeFiles << target.defines << target.files << "\n";
+ qCDebug(log) << target.title << target.sourceDirectory << target.includeFiles
+ << ProjectExplorer::Macro::toByteArray(target.macros)
+ << target.files << "\n";
// find a good build target to fall back
int fallbackIndex = 0;
@@ -153,7 +155,9 @@ void CMakeCbpParser::sortFiles()
qCDebug(log) << "# After Dump #";
qCDebug(log) << "###############";
foreach (const CMakeBuildTarget &target, m_buildTargets)
- qCDebug(log) << target.title << target.sourceDirectory << target.includeFiles << target.defines << target.files << "\n";
+ qCDebug(log) << target.title << target.sourceDirectory << target.includeFiles
+ << ProjectExplorer::Macro::toByteArray(target.macros)
+ << target.files << "\n";
}
bool CMakeCbpParser::parseCbpFile(CMakeTool::PathMapper mapper, const FileName &fileName,
@@ -397,12 +401,8 @@ void CMakeCbpParser::parseAdd()
m_buildTarget.compilerOptions.append(compilerOption);
int macroNameIndex = compilerOption.indexOf("-D") + 2;
if (macroNameIndex != 1) {
- int assignIndex = compilerOption.indexOf('=', macroNameIndex);
- if (assignIndex != -1)
- compilerOption[assignIndex] = ' ';
- m_buildTarget.defines.append("#define ");
- m_buildTarget.defines.append(compilerOption.mid(macroNameIndex).toUtf8());
- m_buildTarget.defines.append('\n');
+ const QString keyValue = compilerOption.mid(macroNameIndex);
+ m_buildTarget.macros.append(ProjectExplorer::Macro::fromKeyValue(keyValue));
}
}
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
index 42226ec6bd..211f564cc8 100644
--- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
@@ -559,7 +559,7 @@ void CMakeBuildTarget::clear()
targetType = UtilityType;
includeFiles.clear();
compilerOptions.clear();
- defines.clear();
+ macros.clear();
files.clear();
}
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h
index cb035dddf8..8083cf9dec 100644
--- a/src/plugins/cmakeprojectmanager/cmakeproject.h
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.h
@@ -30,6 +30,7 @@
#include "treescanner.h"
#include <projectexplorer/extracompiler.h>
+#include <projectexplorer/projectmacro.h>
#include <projectexplorer/project.h>
#include <utils/fileutils.h>
@@ -72,7 +73,7 @@ public:
// code model
QList<Utils::FileName> includeFiles;
QStringList compilerOptions;
- QByteArray defines;
+ ProjectExplorer::Macros macros;
QList<Utils::FileName> files;
void clear();
diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp
index fce7288e07..1b97b6b838 100644
--- a/src/plugins/cmakeprojectmanager/servermodereader.cpp
+++ b/src/plugins/cmakeprojectmanager/servermodereader.cpp
@@ -45,6 +45,8 @@
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
+#include <QVector>
+
using namespace ProjectExplorer;
using namespace Utils;
@@ -325,14 +327,6 @@ void ServerModeReader::updateCodeModel(CppTools::RawProjectParts &rpps)
int counter = 0;
for (const FileGroup *fg : Utils::asConst(m_fileGroups)) {
++counter;
- const QString defineArg
- = transform(fg->defines, [](const QString &s) -> QString {
- QString result = QString::fromLatin1("#define ") + s;
- int assignIndex = result.indexOf('=');
- if (assignIndex != -1)
- result[assignIndex] = ' ';
- return result;
- }).join('\n');
const QStringList flags = QtcProcess::splitArgs(fg->compileFlags);
const QStringList includes = transform(fg->includePaths, [](const IncludePath *ip) { return ip->path.toString(); });
@@ -340,7 +334,7 @@ void ServerModeReader::updateCodeModel(CppTools::RawProjectParts &rpps)
rpp.setProjectFileLocation(fg->target->sourceDirectory.toString() + "/CMakeLists.txt");
rpp.setBuildSystemTarget(fg->target->name);
rpp.setDisplayName(fg->target->name + QString::number(counter));
- rpp.setDefines(defineArg.toUtf8());
+ rpp.setMacros(fg->macros);
rpp.setIncludePaths(includes);
CppTools::RawProjectPartFlags cProjectFlags;
@@ -523,7 +517,9 @@ ServerModeReader::FileGroup *ServerModeReader::extractFileGroupData(const QVaria
auto fileGroup = new FileGroup;
fileGroup->target = t;
fileGroup->compileFlags = data.value("compileFlags").toString();
- fileGroup->defines = data.value("defines").toStringList();
+ fileGroup->macros = Utils::transform<QVector>(data.value("defines").toStringList(), [](const QString &s) {
+ return ProjectExplorer::Macro::fromKeyValue(s);
+ });
fileGroup->includePaths = transform(data.value("includePath").toList(),
[](const QVariant &i) -> IncludePath* {
const QVariantMap iData = i.toMap();
@@ -662,7 +658,7 @@ void ServerModeReader::fixTarget(ServerModeReader::Target *target) const
for (const FileGroup *group : Utils::asConst(target->fileGroups)) {
if (group->includePaths.isEmpty() && group->compileFlags.isEmpty()
- && group->defines.isEmpty())
+ && group->macros.isEmpty())
continue;
const FileGroup *fallback = languageFallbacks.value(group->language);
@@ -688,13 +684,13 @@ void ServerModeReader::fixTarget(ServerModeReader::Target *target) const
(*it)->language = fallback->language.isEmpty() ? "CXX" : fallback->language;
if (*it == fallback
- || !(*it)->includePaths.isEmpty() || !(*it)->defines.isEmpty()
+ || !(*it)->includePaths.isEmpty() || !(*it)->macros.isEmpty()
|| !(*it)->compileFlags.isEmpty())
continue;
for (const IncludePath *ip : fallback->includePaths)
(*it)->includePaths.append(new IncludePath(*ip));
- (*it)->defines = fallback->defines;
+ (*it)->macros = fallback->macros;
(*it)->compileFlags = fallback->compileFlags;
}
}
diff --git a/src/plugins/cmakeprojectmanager/servermodereader.h b/src/plugins/cmakeprojectmanager/servermodereader.h
index 8dc4f5e353..f861483227 100644
--- a/src/plugins/cmakeprojectmanager/servermodereader.h
+++ b/src/plugins/cmakeprojectmanager/servermodereader.h
@@ -86,7 +86,7 @@ private:
Target *target = nullptr;
QString compileFlags;
- QStringList defines;
+ ProjectExplorer::Macros macros;
QList<IncludePath *> includePaths;
QString language;
QList<Utils::FileName> sources;
diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.cpp b/src/plugins/cmakeprojectmanager/tealeafreader.cpp
index ca3794c89d..69b170d38d 100644
--- a/src/plugins/cmakeprojectmanager/tealeafreader.cpp
+++ b/src/plugins/cmakeprojectmanager/tealeafreader.cpp
@@ -384,7 +384,7 @@ void TeaLeafReader::updateCodeModel(CppTools::RawProjectParts &rpps)
cxxProjectFlags.commandLineFlags = cxxflags;
rpp.setFlagsForCxx(cxxProjectFlags);
- rpp.setDefines(cbt.defines);
+ rpp.setMacros(cbt.macros);
rpp.setDisplayName(cbt.title);
rpp.setFiles(transform(cbt.files, [](const FileName &fn) { return fn.toString(); }));
diff --git a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp
index 6283d43d49..51ff075845 100644
--- a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp
+++ b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp
@@ -35,6 +35,7 @@
#include <cpptools/cppmodelmanager.h>
#include <cpptools/cpptoolsbridge.h>
#include <cpptools/cppworkingcopy.h>
+#include <projectexplorer/projectmacro.h>
#include <projectexplorer/project.h>
#include <cplusplus/CppDocument.h>
@@ -49,6 +50,7 @@
#include <QSortFilterProxyModel>
#include <algorithm>
+#include <numeric>
using namespace CPlusPlus;
using namespace CppTools;
@@ -756,7 +758,7 @@ class MacrosModel : public QAbstractListModel
Q_OBJECT
public:
MacrosModel(QObject *parent);
- void configure(const QList<Macro> &macros);
+ void configure(const QList<CPlusPlus::Macro> &macros);
void clear();
enum Columns { LineNumberColumn, MacroColumn, ColumnCount };
@@ -767,14 +769,14 @@ public:
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
- QList<Macro> m_macros;
+ QList<CPlusPlus::Macro> m_macros;
};
MacrosModel::MacrosModel(QObject *parent) : QAbstractListModel(parent)
{
}
-void MacrosModel::configure(const QList<Macro> &macros)
+void MacrosModel::configure(const QList<CPlusPlus::Macro> &macros)
{
emit layoutAboutToBeChanged();
m_macros = macros;
@@ -802,7 +804,7 @@ QVariant MacrosModel::data(const QModelIndex &index, int role) const
{
const int column = index.column();
if (role == Qt::DisplayRole || (role == Qt::ToolTipRole && column == MacroColumn)) {
- const Macro macro = m_macros.at(index.row());
+ const CPlusPlus::Macro macro = m_macros.at(index.row());
if (column == LineNumberColumn)
return macro.line();
else if (column == MacroColumn)
@@ -1614,7 +1616,8 @@ void CppCodeModelInspectorDialog::refresh()
}
// Merged entities
- dumper.dumpMergedEntities(cmmi->headerPaths(), cmmi->definedMacros());
+ dumper.dumpMergedEntities(cmmi->headerPaths(),
+ ProjectExplorer::Macro::toByteArray(cmmi->definedMacros()));
}
enum DocumentTabs {
@@ -1758,6 +1761,15 @@ void CppCodeModelInspectorDialog::clearProjectPartData()
partTabName(ProjectPartPrecompiledHeadersTab));
}
+static int defineCount(const ProjectExplorer::Macros &macros)
+{
+ using ProjectExplorer::Macro;
+ return int(std::count_if(
+ macros.begin(),
+ macros.end(),
+ [](const Macro &macro) { return macro.type == ProjectExplorer::MacroType::Define; }));
+}
+
void CppCodeModelInspectorDialog::updateProjectPartData(const ProjectPart::Ptr &part)
{
QTC_ASSERT(part, return);
@@ -1802,16 +1814,10 @@ void CppCodeModelInspectorDialog::updateProjectPartData(const ProjectPart::Ptr &
m_ui->projectPartTab->setTabText(ProjectPartFilesTab,
partTabName(ProjectPartFilesTab, part->files.size()));
- // Defines
- const QList<QByteArray> defineLines = part->toolchainDefines.split('\n')
- + part->projectDefines.split('\n');
- int numberOfDefines = 0;
- foreach (const QByteArray &line, defineLines) {
- if (line.startsWith("#define "))
- ++numberOfDefines;
- }
- m_ui->partToolchainDefinesEdit->setPlainText(QString::fromUtf8(part->toolchainDefines));
- m_ui->partProjectDefinesEdit->setPlainText(QString::fromUtf8(part->projectDefines));
+ int numberOfDefines = defineCount(part->toolChainMacros) + defineCount(part->projectMacros);
+
+ m_ui->partToolchainDefinesEdit->setPlainText(QString::fromUtf8(ProjectExplorer::Macro::toByteArray(part->toolChainMacros)));
+ m_ui->partProjectDefinesEdit->setPlainText(QString::fromUtf8(ProjectExplorer::Macro::toByteArray(part->projectMacros)));
m_ui->projectPartTab->setTabText(ProjectPartDefinesTab,
partTabName(ProjectPartDefinesTab, numberOfDefines));
diff --git a/src/plugins/cpptools/builtineditordocumentparser.cpp b/src/plugins/cpptools/builtineditordocumentparser.cpp
index ac3cf3ee2a..3fb407cb2d 100644
--- a/src/plugins/cpptools/builtineditordocumentparser.cpp
+++ b/src/plugins/cpptools/builtineditordocumentparser.cpp
@@ -26,6 +26,7 @@
#include "builtineditordocumentparser.h"
#include "cppsourceprocessor.h"
+#include <projectexplorer/projectmacro.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <utils/qtcassert.h>
@@ -91,9 +92,9 @@ void BuiltinEditorDocumentParser::updateImpl(const QFutureInterface<void> &futur
}
if (const ProjectPart::Ptr part = baseState.projectPartInfo.projectPart) {
- configFile += part->toolchainDefines;
+ configFile += ProjectExplorer::Macro::toByteArray(part->toolChainMacros);
configFile += overwrittenToolchainDefines(*part.data());
- configFile += part->projectDefines;
+ configFile += ProjectExplorer::Macro::toByteArray(part->projectMacros);
if (!part->projectConfigFile.isEmpty())
configFile += ProjectPart::readProjectConfigFile(part);
headerPaths = part->headerPaths;
diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp
index 170279c9b8..079f76fc6a 100644
--- a/src/plugins/cpptools/compileroptionsbuilder.cpp
+++ b/src/plugins/cpptools/compileroptionsbuilder.cpp
@@ -48,44 +48,9 @@ void CompilerOptionsBuilder::add(const QString &option)
m_options.append(option);
}
-struct Macro {
- static Macro fromDefineDirective(const QByteArray &defineDirective);
- QByteArray toDefineOption(const QByteArray &option) const;
-
- QByteArray name;
- QByteArray value;
-};
-
-Macro Macro::fromDefineDirective(const QByteArray &defineDirective)
+void CompilerOptionsBuilder::addDefine(const ProjectExplorer::Macro &macro)
{
- const QByteArray str = defineDirective.mid(8);
- const int spaceIdx = str.indexOf(' ');
- const bool hasValue = spaceIdx != -1;
-
- Macro macro;
- macro.name = str.left(hasValue ? spaceIdx : str.size());
- if (hasValue)
- macro.value = str.mid(spaceIdx + 1);
-
- return macro;
-}
-
-QByteArray Macro::toDefineOption(const QByteArray &option) const
-{
- QByteArray result;
-
- result.append(option);
- result.append(name);
- result.append('=');
- if (!value.isEmpty())
- result.append(value);
-
- return result;
-}
-
-void CompilerOptionsBuilder::addDefine(const QByteArray &defineDirective)
-{
- m_options.append(defineDirectiveToDefineOption(defineDirective));
+ m_options.append(defineDirectiveToDefineOption(macro));
}
void CompilerOptionsBuilder::addWordWidth()
@@ -162,19 +127,19 @@ void CompilerOptionsBuilder::addPrecompiledHeaderOptions(PchUsage pchUsage)
void CompilerOptionsBuilder::addToolchainAndProjectDefines()
{
- addDefines(m_projectPart.toolchainDefines);
- addDefines(m_projectPart.projectDefines);
+ addMacros(m_projectPart.toolChainMacros);
+ addMacros(m_projectPart.projectMacros);
}
-void CompilerOptionsBuilder::addDefines(const QByteArray &defineDirectives)
+void CompilerOptionsBuilder::addMacros(const ProjectExplorer::Macros &macros)
{
QStringList result;
- foreach (QByteArray def, defineDirectives.split('\n')) {
- if (def.isEmpty() || excludeDefineDirective(def))
+ for (const ProjectExplorer::Macro &macro : macros) {
+ if (excludeDefineDirective(macro))
continue;
- const QString defineOption = defineDirectiveToDefineOption(def);
+ const QString defineOption = defineDirectiveToDefineOption(macro);
if (!result.contains(defineOption))
result.append(defineOption);
}
@@ -303,8 +268,8 @@ void CompilerOptionsBuilder::addDefineToAvoidIncludingGccOrMinGwIntrinsics()
const Core::Id type = m_projectPart.toolchainType;
if (type == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID
|| type == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID) {
- addDefine("#define _X86INTRIN_H_INCLUDED");
- addDefine("#define BOOST_UUID_NO_SIMD");
+ addDefine({"_X86INTRIN_H_INCLUDED"});
+ addDefine({"BOOST_UUID_NO_SIMD"});
}
}
@@ -315,14 +280,10 @@ static QByteArray toMsCompatibilityVersionFormat(const QByteArray &mscFullVer)
+ mscFullVer.mid(2, 2);
}
-static QByteArray msCompatibilityVersionFromDefines(const QByteArray &defineDirectives)
+static QByteArray msCompatibilityVersionFromDefines(const ProjectExplorer::Macros &macros)
{
- foreach (QByteArray defineDirective, defineDirectives.split('\n')) {
- if (defineDirective.isEmpty())
- continue;
-
- const Macro macro = Macro::fromDefineDirective(defineDirective);
- if (macro.name == "_MSC_FULL_VER")
+ for (const ProjectExplorer::Macro &macro : macros) {
+ if (macro.key == "_MSC_FULL_VER")
return toMsCompatibilityVersionFormat(macro.value);
}
@@ -332,8 +293,8 @@ static QByteArray msCompatibilityVersionFromDefines(const QByteArray &defineDire
void CompilerOptionsBuilder::addMsvcCompatibilityVersion()
{
if (m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) {
- const QByteArray defines = m_projectPart.toolchainDefines + m_projectPart.projectDefines;
- const QByteArray msvcVersion = msCompatibilityVersionFromDefines(defines);
+ const ProjectExplorer::Macros macros = m_projectPart.toolChainMacros + m_projectPart.projectMacros;
+ const QByteArray msvcVersion = msCompatibilityVersionFromDefines(macros);
if (!msvcVersion.isEmpty()) {
const QString option = QLatin1String("-fms-compatibility-version=")
@@ -398,7 +359,7 @@ void CompilerOptionsBuilder::addDefineFloat128ForMingw()
// CLANG-UPGRADE-CHECK: Workaround still needed?
// https://llvm.org/bugs/show_bug.cgi?id=30685
if (m_projectPart.toolchainType == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID)
- addDefine("#define __float128 short");
+ addDefine({"__float128", "short", ProjectExplorer::MacroType::Define});
}
QString CompilerOptionsBuilder::includeDirOption() const
@@ -406,12 +367,25 @@ QString CompilerOptionsBuilder::includeDirOption() const
return QLatin1String("-I");
}
-QString CompilerOptionsBuilder::defineDirectiveToDefineOption(const QByteArray &defineDirective)
+QByteArray CompilerOptionsBuilder::macroOption(const ProjectExplorer::Macro &macro) const
+{
+ switch (macro.type) {
+ case ProjectExplorer::MacroType::Define: return defineOption().toUtf8();
+ case ProjectExplorer::MacroType::Undefine: return undefineOption().toUtf8();
+ default: return QByteArray();
+ }
+}
+
+QByteArray CompilerOptionsBuilder::toDefineOption(const ProjectExplorer::Macro &macro) const
+{
+ return macro.toKeyValue(macroOption(macro));
+}
+
+QString CompilerOptionsBuilder::defineDirectiveToDefineOption(const ProjectExplorer::Macro &macro) const
{
- const Macro macro = Macro::fromDefineDirective(defineDirective);
- const QByteArray option = macro.toDefineOption(defineOption().toLatin1());
+ const QByteArray option = toDefineOption(macro);
- return QString::fromLatin1(option);
+ return QString::fromUtf8(option);
}
QString CompilerOptionsBuilder::defineOption() const
@@ -435,11 +409,11 @@ static bool isGccOrMinGwToolchain(const Core::Id &toolchainType)
|| toolchainType == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID;
}
-bool CompilerOptionsBuilder::excludeDefineDirective(const QByteArray &defineDirective) const
+bool CompilerOptionsBuilder::excludeDefineDirective(const ProjectExplorer::Macro &macro) const
{
// This is a quick fix for QTCREATORBUG-11501.
// TODO: do a proper fix, see QTCREATORBUG-11709.
- if (defineDirective.startsWith("#define __cplusplus"))
+ if (macro.key == "__cplusplus")
return true;
// gcc 4.9 has:
@@ -449,7 +423,7 @@ bool CompilerOptionsBuilder::excludeDefineDirective(const QByteArray &defineDire
// override clang's own (non-macro, it seems) definitions of the symbols on the left-hand
// side.
if (isGccOrMinGwToolchain(m_projectPart.toolchainType)
- && defineDirective.contains("has_include")) {
+ && macro.key.contains("has_include")) {
return true;
}
@@ -459,14 +433,14 @@ bool CompilerOptionsBuilder::excludeDefineDirective(const QByteArray &defineDire
// __builtin_va_arg_pack, which clang does not support (yet), so avoid
// including those.
if (m_projectPart.toolchainType == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID
- && defineDirective.startsWith("#define _FORTIFY_SOURCE")) {
+ && macro.key == "_FORTIFY_SOURCE") {
return true;
}
// MinGW 6 supports some fancy asm output flags and uses them in an
// intrinsics header pulled in by windows.h. Clang does not know them.
if (m_projectPart.toolchainType == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID
- && defineDirective.startsWith("#define __GCC_ASM_FLAG_OUTPUTS__")) {
+ && macro.key == "__GCC_ASM_FLAG_OUTPUTS__") {
return true;
}
diff --git a/src/plugins/cpptools/compileroptionsbuilder.h b/src/plugins/cpptools/compileroptionsbuilder.h
index 75b0c4f530..48c23b3e91 100644
--- a/src/plugins/cpptools/compileroptionsbuilder.h
+++ b/src/plugins/cpptools/compileroptionsbuilder.h
@@ -46,7 +46,7 @@ public:
// Add custom options
void add(const QString &option);
- void addDefine(const QByteArray &defineDirective);
+ void addDefine(const ProjectExplorer::Macro &marco);
// Add options based on project part
void addWordWidth();
@@ -55,7 +55,7 @@ public:
void addHeaderPathOptions();
void addPrecompiledHeaderOptions(PchUsage pchUsage);
void addToolchainAndProjectDefines();
- void addDefines(const QByteArray &defineDirectives);
+ void addMacros(const ProjectExplorer::Macros &macros);
virtual void addLanguageOption(ProjectFile::Kind fileKind);
virtual void addOptionsForLanguage(bool checkForBorlandExtensions = true);
@@ -67,7 +67,7 @@ public:
void addDefineFloat128ForMingw();
protected:
- virtual bool excludeDefineDirective(const QByteArray &defineDirective) const;
+ virtual bool excludeDefineDirective(const ProjectExplorer::Macro &macro) const;
virtual bool excludeHeaderPath(const QString &headerPath) const;
virtual QString defineOption() const;
@@ -78,7 +78,9 @@ protected:
const ProjectPart m_projectPart;
private:
- QString defineDirectiveToDefineOption(const QByteArray &defineDirective);
+ QByteArray macroOption(const ProjectExplorer::Macro &macro) const;
+ QByteArray toDefineOption(const ProjectExplorer::Macro &macro) const;
+ QString defineDirectiveToDefineOption(const ProjectExplorer::Macro &marco) const;
QStringList m_options;
};
diff --git a/src/plugins/cpptools/cppcodemodelinspectordumper.cpp b/src/plugins/cpptools/cppcodemodelinspectordumper.cpp
index 199f185d63..8797a2ba63 100644
--- a/src/plugins/cpptools/cppcodemodelinspectordumper.cpp
+++ b/src/plugins/cpptools/cppcodemodelinspectordumper.cpp
@@ -31,6 +31,7 @@
#include <app/app_version.h>
#include <coreplugin/icore.h>
#include <cpptools/cppprojectfile.h>
+#include <projectexplorer/projectmacro.h>
#include <projectexplorer/project.h>
#include <utils/algorithm.h>
#include <utils/temporarydirectory.h>
@@ -495,15 +496,17 @@ void Dumper::dumpProjectInfos( const QList<ProjectInfo> &projectInfos)
}
}
- if (!part->toolchainDefines.isEmpty()) {
+ if (!part->toolChainMacros.isEmpty()) {
m_out << i3 << "Toolchain Defines:{{{4\n";
- const QList<QByteArray> defineLines = part->toolchainDefines.split('\n');
+ const QList<QByteArray> defineLines =
+ ProjectExplorer::Macro::toByteArray(part->toolChainMacros).split('\n');
foreach (const QByteArray &defineLine, defineLines)
m_out << i4 << defineLine << "\n";
}
- if (!part->projectDefines.isEmpty()) {
+ if (!part->projectMacros.isEmpty()) {
m_out << i3 << "Project Defines:{{{4\n";
- const QList<QByteArray> defineLines = part->projectDefines.split('\n');
+ const QList<QByteArray> defineLines =
+ ProjectExplorer::Macro::toByteArray(part->projectMacros).split('\n');
foreach (const QByteArray &defineLine, defineLines)
m_out << i4 << defineLine << "\n";
}
diff --git a/src/plugins/cpptools/cppcompletionassist.cpp b/src/plugins/cpptools/cppcompletionassist.cpp
index 26b139e647..3e1c19399e 100644
--- a/src/plugins/cpptools/cppcompletionassist.cpp
+++ b/src/plugins/cpptools/cppcompletionassist.cpp
@@ -1902,7 +1902,7 @@ void InternalCppCompletionAssistProcessor::addMacros_helper(const Snapshot &snap
foreach (const Document::Include &i, doc->resolvedIncludes())
addMacros_helper(snapshot, i.resolvedFileName(), processed, definedMacros);
- foreach (const Macro &macro, doc->definedMacros()) {
+ foreach (const CPlusPlus::Macro &macro, doc->definedMacros()) {
const QString macroName = macro.nameToQString();
if (!macro.isHidden())
definedMacros->insert(macroName);
diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp
index a27233f1c1..9e521ac46f 100644
--- a/src/plugins/cpptools/cppfindreferences.cpp
+++ b/src/plugins/cpptools/cppfindreferences.cpp
@@ -607,13 +607,13 @@ class FindMacroUsesInFile: public std::unary_function<QString, QList<Usage> >
{
const WorkingCopy workingCopy;
const Snapshot snapshot;
- const Macro &macro;
+ const CPlusPlus::Macro &macro;
QFutureInterface<Usage> *future;
public:
FindMacroUsesInFile(const WorkingCopy &workingCopy,
const Snapshot snapshot,
- const Macro &macro,
+ const CPlusPlus::Macro &macro,
QFutureInterface<Usage> *future)
: workingCopy(workingCopy), snapshot(snapshot), macro(macro), future(future)
{ }
@@ -632,7 +632,7 @@ restart_search:
usages.clear();
foreach (const Document::MacroUse &use, doc->macroUses()) {
- const Macro &useMacro = use.macro();
+ const CPlusPlus::Macro &useMacro = use.macro();
if (useMacro.fileName() == macro.fileName()) { // Check if this is a match, but possibly against an outdated document.
if (source.isEmpty())
@@ -687,7 +687,7 @@ restart_search:
static void findMacroUses_helper(QFutureInterface<Usage> &future,
const WorkingCopy workingCopy,
const Snapshot snapshot,
- const Macro macro)
+ const CPlusPlus::Macro macro)
{
const Utils::FileName sourceFile = Utils::FileName::fromString(macro.fileName());
Utils::FileNameList files{sourceFile};
@@ -704,12 +704,13 @@ static void findMacroUses_helper(QFutureInterface<Usage> &future,
future.setProgressValue(files.size());
}
-void CppFindReferences::findMacroUses(const Macro &macro)
+void CppFindReferences::findMacroUses(const CPlusPlus::Macro &macro)
{
findMacroUses(macro, QString(), false);
}
-void CppFindReferences::findMacroUses(const Macro &macro, const QString &replacement, bool replace)
+void CppFindReferences::findMacroUses(const CPlusPlus::Macro &macro, const QString &replacement,
+ bool replace)
{
SearchResult *search = SearchResultWindow::instance()->startNewSearch(
tr("C++ Macro Usages:"),
@@ -753,7 +754,7 @@ void CppFindReferences::findMacroUses(const Macro &macro, const QString &replace
connect(progress, &FutureProgress::clicked, search, &SearchResult::popup);
}
-void CppFindReferences::renameMacroUses(const Macro &macro, const QString &replacement)
+void CppFindReferences::renameMacroUses(const CPlusPlus::Macro &macro, const QString &replacement)
{
const QString textToReplace = replacement.isEmpty() ? macro.nameToQString() : replacement;
findMacroUses(macro, textToReplace, true);
diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp
index d2493e2e45..08799709b1 100644
--- a/src/plugins/cpptools/cppmodelmanager.cpp
+++ b/src/plugins/cpptools/cppmodelmanager.cpp
@@ -47,6 +47,7 @@
#include <texteditor/textdocument.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectmacro.h>
#include <projectexplorer/session.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/fileutils.h>
@@ -138,7 +139,7 @@ public:
bool m_dirty;
QStringList m_projectFiles;
ProjectPartHeaderPaths m_headerPaths;
- QByteArray m_definedMacros;
+ ProjectExplorer::Macros m_definedMacros;
// Editor integration
mutable QMutex m_cppEditorDocumentsMutex;
@@ -446,35 +447,31 @@ ProjectPartHeaderPaths CppModelManager::internalHeaderPaths() const
return headerPaths;
}
-static void addUnique(const QList<QByteArray> &defs, QByteArray *macros, QSet<QByteArray> *alreadyIn)
+static void addUnique(const ProjectExplorer::Macros &newMacros,
+ ProjectExplorer::Macros &macros,
+ QSet<ProjectExplorer::Macro> &alreadyIn)
{
- Q_ASSERT(macros);
- Q_ASSERT(alreadyIn);
-
- foreach (const QByteArray &def, defs) {
- if (def.trimmed().isEmpty())
- continue;
- if (!alreadyIn->contains(def)) {
- macros->append(def);
- macros->append('\n');
- alreadyIn->insert(def);
+ for (const ProjectExplorer::Macro &macro : newMacros) {
+ if (!alreadyIn.contains(macro)) {
+ macros += macro;
+ alreadyIn.insert(macro);
}
}
}
-QByteArray CppModelManager::internalDefinedMacros() const
+ProjectExplorer::Macros CppModelManager::internalDefinedMacros() const
{
- QByteArray macros;
- QSet<QByteArray> alreadyIn;
+ ProjectExplorer::Macros macros;
+ QSet<ProjectExplorer::Macro> alreadyIn;
QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(d->m_projectToProjectsInfo);
while (it.hasNext()) {
it.next();
const ProjectInfo pinfo = it.value();
- foreach (const ProjectPart::Ptr &part, pinfo.projectParts()) {
- addUnique(part->toolchainDefines.split('\n'), &macros, &alreadyIn);
- addUnique(part->projectDefines.split('\n'), &macros, &alreadyIn);
+ for (const ProjectPart::Ptr &part : pinfo.projectParts()) {
+ addUnique(part->toolChainMacros, macros, alreadyIn);
+ addUnique(part->projectMacros, macros, alreadyIn);
if (!part->projectConfigFile.isEmpty())
- macros += ProjectPart::readProjectConfigFile(part);
+ macros += ProjectExplorer::Macro::toMacros(ProjectPart::readProjectConfigFile(part));
}
}
return macros;
@@ -491,7 +488,8 @@ void CppModelManager::dumpModelManagerConfiguration(const QString &logFileId)
dumper.dumpProjectInfos(projectInfos());
dumper.dumpSnapshot(globalSnapshot, globalSnapshotTitle, /*isGlobalSnapshot=*/ true);
dumper.dumpWorkingCopy(workingCopy());
- dumper.dumpMergedEntities(headerPaths(), definedMacros());
+ dumper.dumpMergedEntities(headerPaths(),
+ ProjectExplorer:: Macro::toByteArray(definedMacros()));
}
QSet<AbstractEditorSupport *> CppModelManager::abstractEditorSupports() const
@@ -569,12 +567,12 @@ void CppModelManager::renameUsages(Symbol *symbol,
d->m_findReferences->renameUsages(symbol, context, replacement);
}
-void CppModelManager::findMacroUsages(const Macro &macro)
+void CppModelManager::findMacroUsages(const CPlusPlus::Macro &macro)
{
d->m_findReferences->findMacroUses(macro);
}
-void CppModelManager::renameMacroUsages(const Macro &macro, const QString &replacement)
+void CppModelManager::renameMacroUsages(const CPlusPlus::Macro &macro, const QString &replacement)
{
d->m_findReferences->renameMacroUses(macro, replacement);
}
@@ -603,7 +601,7 @@ WorkingCopy CppModelManager::buildWorkingCopyList()
// Add the project configuration file
QByteArray conf = codeModelConfiguration();
- conf += definedMacros();
+ conf += ProjectExplorer::Macro::toByteArray(definedMacros());
workingCopy.insert(configurationFileName(), conf);
return workingCopy;
@@ -991,7 +989,7 @@ ProjectPart::Ptr CppModelManager::fallbackProjectPart()
{
ProjectPart::Ptr part(new ProjectPart);
- part->projectDefines = definedMacros();
+ part->projectMacros = definedMacros();
part->headerPaths = headerPaths();
// Do not activate ObjectiveCExtensions since this will lead to the
@@ -1270,7 +1268,7 @@ void CppModelManager::setHeaderPaths(const ProjectPartHeaderPaths &headerPaths)
d->m_headerPaths = headerPaths;
}
-QByteArray CppModelManager::definedMacros()
+ProjectExplorer::Macros CppModelManager::definedMacros()
{
QMutexLocker locker(&d->m_projectMutex);
ensureUpdated();
diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h
index 97a93fce60..1cabaf50ef 100644
--- a/src/plugins/cpptools/cppmodelmanager.h
+++ b/src/plugins/cpptools/cppmodelmanager.h
@@ -163,7 +163,7 @@ public:
// Use this *only* for auto tests
void setHeaderPaths(const ProjectPartHeaderPaths &headerPaths);
- QByteArray definedMacros();
+ ProjectExplorer::Macros definedMacros();
void enableGarbageCollector(bool enable);
@@ -229,7 +229,7 @@ private:
void ensureUpdated();
QStringList internalProjectFiles() const;
ProjectPartHeaderPaths internalHeaderPaths() const;
- QByteArray internalDefinedMacros() const;
+ ProjectExplorer::Macros internalDefinedMacros() const;
void dumpModelManagerConfiguration(const QString &logFileId);
diff --git a/src/plugins/cpptools/cppmodelmanager_test.cpp b/src/plugins/cpptools/cppmodelmanager_test.cpp
index 35f9931f21..c50c12402c 100644
--- a/src/plugins/cpptools/cppmodelmanager_test.cpp
+++ b/src/plugins/cpptools/cppmodelmanager_test.cpp
@@ -187,7 +187,7 @@ void CppToolsPlugin::test_modelmanager_paths_are_clean()
ProjectPart::Ptr part(new ProjectPart);
part->qtVersion = ProjectPart::Qt5;
- part->projectDefines = QByteArray("#define OH_BEHAVE -1\n");
+ part->projectMacros = {ProjectExplorer::Macro("OH_BEHAVE", "-1")};
part->headerPaths = {HeaderPath(testDataDir.includeDir(false), HeaderPath::IncludePath),
HeaderPath(testDataDir.frameworksDir(false), HeaderPath::FrameworkPath)};
pi.appendProjectPart(part);
@@ -219,7 +219,7 @@ void CppToolsPlugin::test_modelmanager_framework_headers()
ProjectPart::Ptr part(new ProjectPart);
part->qtVersion = ProjectPart::Qt5;
- part->projectDefines = QByteArray("#define OH_BEHAVE -1\n");
+ part->projectMacros = {{"OH_BEHAVE", "-1"}};
part->headerPaths = {HeaderPath(testDataDir.includeDir(false), HeaderPath::IncludePath),
HeaderPath(testDataDir.frameworksDir(false), HeaderPath::FrameworkPath)};
const QString &source = testDataDir.fileFromSourcesDir(
@@ -268,7 +268,7 @@ void CppToolsPlugin::test_modelmanager_refresh_also_includes_of_project_files()
ProjectPart::Ptr part(new ProjectPart);
part->qtVersion = ProjectPart::Qt5;
- part->projectDefines = QByteArray("#define OH_BEHAVE -1\n");
+ part->projectMacros = {{"OH_BEHAVE", "-1"}};
part->headerPaths = {HeaderPath(testDataDir.includeDir(false), HeaderPath::IncludePath)};
part->files.append(ProjectFile(testCpp, ProjectFile::CXXSource));
pi.appendProjectPart(part);
@@ -286,7 +286,7 @@ void CppToolsPlugin::test_modelmanager_refresh_also_includes_of_project_files()
QVERIFY(macrosInHeaderBefore.first().name() == "test_modelmanager_refresh_h");
// Introduce a define that will enable another define once the document is reparsed.
- part->projectDefines = QByteArray("#define TEST_DEFINE 1\n");
+ part->projectMacros = {{"TEST_DEFINE", "1"}};
pi = ProjectInfo(project);
pi.appendProjectPart(part);
@@ -334,13 +334,13 @@ void CppToolsPlugin::test_modelmanager_refresh_several_times()
QSet<QString> refreshedFiles;
CPlusPlus::Document::Ptr document;
- QByteArray defines = "#define FIRST_DEFINE";
+ ProjectExplorer::Macros macros = {{"FIRST_DEFINE"}};
for (int i = 0; i < 2; ++i) {
pi = ProjectInfo(project);
ProjectPart::Ptr part(new ProjectPart);
// Simulate project configuration change by having different defines each time.
- defines += "\n#define ANOTHER_DEFINE";
- part->projectDefines = defines;
+ macros += {"ANOTHER_DEFINE"};
+ part->projectMacros = macros;
part->qtVersion = ProjectPart::Qt5;
part->files.append(ProjectFile(testHeader1, ProjectFile::CXXHeader));
part->files.append(ProjectFile(testHeader2, ProjectFile::CXXHeader));
@@ -762,7 +762,7 @@ void CppToolsPlugin::test_modelmanager_defines_per_project()
part1->files.append(ProjectFile(main1File, ProjectFile::CXXSource));
part1->files.append(ProjectFile(header, ProjectFile::CXXHeader));
part1->qtVersion = ProjectPart::NoQt;
- part1->projectDefines = QByteArray("#define SUB1\n");
+ part1->projectMacros = {{"SUB1"}};
part1->headerPaths = {HeaderPath(testDataDirectory.includeDir(false), HeaderPath::IncludePath)};
ProjectPart::Ptr part2(new ProjectPart);
@@ -770,7 +770,7 @@ void CppToolsPlugin::test_modelmanager_defines_per_project()
part2->files.append(ProjectFile(main2File, ProjectFile::CXXSource));
part2->files.append(ProjectFile(header, ProjectFile::CXXHeader));
part2->qtVersion = ProjectPart::NoQt;
- part2->projectDefines = QByteArray("#define SUB2\n");
+ part2->projectMacros = {{"SUB2"}};
part2->headerPaths = {HeaderPath(testDataDirectory.includeDir(false), HeaderPath::IncludePath)};
ProjectInfo pi = ProjectInfo(project);
diff --git a/src/plugins/cpptools/cppprojectinfogenerator.cpp b/src/plugins/cpptools/cppprojectinfogenerator.cpp
index bff5d36ec4..3c8ac37654 100644
--- a/src/plugins/cpptools/cppprojectinfogenerator.cpp
+++ b/src/plugins/cpptools/cppprojectinfogenerator.cpp
@@ -143,7 +143,7 @@ private:
if (!m_tcInfo.predefinedMacrosRunner)
return; // No compiler set in kit.
- m_projectPart.toolchainDefines = m_tcInfo.predefinedMacrosRunner(m_flags.commandLineFlags);
+ m_projectPart.toolChainMacros = m_tcInfo.predefinedMacrosRunner(m_flags.commandLineFlags);
}
private:
@@ -187,7 +187,7 @@ static ProjectPart::Ptr projectPartFromRawProjectPart(const RawProjectPart &rawP
part->callGroupId = rawProjectPart.callGroupId;
part->buildSystemTarget = rawProjectPart.buildSystemTarget;
part->qtVersion = rawProjectPart.qtVersion;
- part->projectDefines = rawProjectPart.projectDefines;
+ part->projectMacros = rawProjectPart.projectMacros;
part->headerPaths = rawProjectPart.headerPaths;
part->precompiledHeaders = rawProjectPart.precompiledHeaders;
part->selectedForBuilding = rawProjectPart.selectedForBuilding;
diff --git a/src/plugins/cpptools/cpprawprojectpart.cpp b/src/plugins/cpptools/cpprawprojectpart.cpp
index 3668f8caec..001bf01af3 100644
--- a/src/plugins/cpptools/cpprawprojectpart.cpp
+++ b/src/plugins/cpptools/cpprawprojectpart.cpp
@@ -81,9 +81,9 @@ void RawProjectPart::setQtVersion(ProjectPart::QtVersion qtVersion)
this->qtVersion = qtVersion;
}
-void RawProjectPart::setDefines(const QByteArray &defines)
+void RawProjectPart::setMacros(const ProjectExplorer::Macros &macros)
{
- this->projectDefines = defines;
+ this->projectMacros = macros;
}
void RawProjectPart::setHeaderPaths(const ProjectPartHeaderPaths &headerPaths)
diff --git a/src/plugins/cpptools/cpprawprojectpart.h b/src/plugins/cpptools/cpprawprojectpart.h
index 18f0591ec2..aafe74281d 100644
--- a/src/plugins/cpptools/cpprawprojectpart.h
+++ b/src/plugins/cpptools/cpprawprojectpart.h
@@ -67,7 +67,7 @@ public:
void setQtVersion(ProjectPart::QtVersion qtVersion);
- void setDefines(const QByteArray &defines);
+ void setMacros(const ProjectExplorer::Macros &macros);
void setHeaderPaths(const ProjectPartHeaderPaths &headerPaths);
void setIncludePaths(const QStringList &includePaths);
@@ -88,7 +88,7 @@ public:
QString buildSystemTarget;
QStringList precompiledHeaders;
ProjectPartHeaderPaths headerPaths;
- QByteArray projectDefines;
+ ProjectExplorer::Macros projectMacros;
ProjectPart::QtVersion qtVersion = ProjectPart::UnknownQt;
bool selectedForBuilding = true;
diff --git a/src/plugins/cpptools/cppsourceprocessor.cpp b/src/plugins/cpptools/cppsourceprocessor.cpp
index fc28a6135e..507e33c90b 100644
--- a/src/plugins/cpptools/cppsourceprocessor.cpp
+++ b/src/plugins/cpptools/cppsourceprocessor.cpp
@@ -62,11 +62,12 @@ static Q_LOGGING_CATEGORY(log, "qtc.cpptools.sourceprocessor")
namespace {
-inline QByteArray generateFingerPrint(const QList<Macro> &definedMacros, const QByteArray &code)
+inline QByteArray generateFingerPrint(const QList<CPlusPlus::Macro> &definedMacros,
+ const QByteArray &code)
{
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(code);
- foreach (const Macro &macro, definedMacros) {
+ foreach (const CPlusPlus::Macro &macro, definedMacros) {
if (macro.isHidden()) {
static const QByteArray undef("#undef ");
hash.addData(undef);
@@ -98,10 +99,10 @@ inline Message messageNoFileContents(Document::Ptr &document, const QString &fil
return Message(Message::Warning, document->fileName(), line, /*column =*/ 0, text);
}
-inline const Macro revision(const WorkingCopy &workingCopy,
- const Macro &macro)
+inline const CPlusPlus::Macro revision(const WorkingCopy &workingCopy,
+ const CPlusPlus::Macro &macro)
{
- Macro newMacro(macro);
+ CPlusPlus::Macro newMacro(macro);
newMacro.setFileRevision(workingCopy.get(macro.fileName()).second);
return newMacro;
}
@@ -316,7 +317,7 @@ QString CppSourceProcessor::resolveFile_helper(const QString &fileName,
return QString();
}
-void CppSourceProcessor::macroAdded(const Macro &macro)
+void CppSourceProcessor::macroAdded(const CPlusPlus::Macro &macro)
{
if (!m_currentDoc)
return;
@@ -325,7 +326,7 @@ void CppSourceProcessor::macroAdded(const Macro &macro)
}
void CppSourceProcessor::passedMacroDefinitionCheck(unsigned bytesOffset, unsigned utf16charsOffset,
- unsigned line, const Macro &macro)
+ unsigned line, const CPlusPlus::Macro &macro)
{
if (!m_currentDoc)
return;
@@ -347,7 +348,7 @@ void CppSourceProcessor::failedMacroDefinitionCheck(unsigned bytesOffset, unsign
}
void CppSourceProcessor::notifyMacroReference(unsigned bytesOffset, unsigned utf16charOffset,
- unsigned line, const Macro &macro)
+ unsigned line, const CPlusPlus::Macro &macro)
{
if (!m_currentDoc)
return;
@@ -359,7 +360,7 @@ void CppSourceProcessor::notifyMacroReference(unsigned bytesOffset, unsigned utf
}
void CppSourceProcessor::startExpandingMacro(unsigned bytesOffset, unsigned utf16charOffset,
- unsigned line, const Macro &macro,
+ unsigned line, const CPlusPlus::Macro &macro,
const QVector<MacroArgumentReference> &actuals)
{
if (!m_currentDoc)
@@ -371,7 +372,7 @@ void CppSourceProcessor::startExpandingMacro(unsigned bytesOffset, unsigned utf1
line, actuals);
}
-void CppSourceProcessor::stopExpandingMacro(unsigned, const Macro &)
+void CppSourceProcessor::stopExpandingMacro(unsigned, const CPlusPlus::Macro &)
{
if (!m_currentDoc)
return;
diff --git a/src/plugins/cpptools/cpptoolsunittestfiles.pri b/src/plugins/cpptools/cpptoolsunittestfiles.pri
index 6960ccbde9..48c70fce6e 100644
--- a/src/plugins/cpptools/cpptoolsunittestfiles.pri
+++ b/src/plugins/cpptools/cpptoolsunittestfiles.pri
@@ -1,11 +1,7 @@
-# Currently there are no tests for the project explorer plugin, but we include
-# headers from it that needs to have the export/import adapted for Windows.
shared {
DEFINES += CPPTOOLS_LIBRARY
- DEFINES += PROJECTEXPLORER_LIBRARY
} else {
DEFINES += CPPTOOLS_STATIC_LIBRARY
- DEFINES += PROJECTEXPLORER_STATIC_LIBRARY
}
HEADERS += \
diff --git a/src/plugins/cpptools/projectinfo.cpp b/src/plugins/cpptools/projectinfo.cpp
index 1ca95e3e9c..e0dbee363f 100644
--- a/src/plugins/cpptools/projectinfo.cpp
+++ b/src/plugins/cpptools/projectinfo.cpp
@@ -160,13 +160,10 @@ void ProjectInfo::finish()
m_sourceFiles.insert(file.path);
// Update defines
- m_defines.append(part->toolchainDefines);
- m_defines.append(part->projectDefines);
- if (!part->projectConfigFile.isEmpty()) {
- m_defines.append('\n');
- m_defines += ProjectPart::readProjectConfigFile(part);
- m_defines.append('\n');
- }
+ m_defines.append(part->toolChainMacros);
+ m_defines.append(part->projectMacros);
+ if (!part->projectConfigFile.isEmpty())
+ m_defines += ProjectExplorer::Macro::toMacros(ProjectPart::readProjectConfigFile(part));
}
}
diff --git a/src/plugins/cpptools/projectinfo.h b/src/plugins/cpptools/projectinfo.h
index 9096322989..ee016f5b3e 100644
--- a/src/plugins/cpptools/projectinfo.h
+++ b/src/plugins/cpptools/projectinfo.h
@@ -123,7 +123,7 @@ private:
// The members below are (re)calculated from the project parts with finish()
ProjectPartHeaderPaths m_headerPaths;
QSet<QString> m_sourceFiles;
- QByteArray m_defines;
+ ProjectExplorer::Macros m_defines;
};
} // namespace CppTools
diff --git a/src/plugins/cpptools/projectpart.cpp b/src/plugins/cpptools/projectpart.cpp
index 6a87adf93f..e77e079c80 100644
--- a/src/plugins/cpptools/projectpart.cpp
+++ b/src/plugins/cpptools/projectpart.cpp
@@ -25,6 +25,8 @@
#include "projectpart.h"
+#include <utils/algorithm.h>
+
#include <QFile>
#include <QDir>
#include <QTextStream>
@@ -43,16 +45,9 @@ void ProjectPart::updateLanguageFeatures()
if (!hasQt) {
languageFeatures.qtKeywordsEnabled = false;
} else {
- const QByteArray noKeywordsMacro = "#define QT_NO_KEYWORDS";
- const int noKeywordsIndex = projectDefines.indexOf(noKeywordsMacro);
- if (noKeywordsIndex == -1) {
- languageFeatures.qtKeywordsEnabled = true;
- } else {
- const char nextChar = projectDefines.at(noKeywordsIndex + noKeywordsMacro.length());
- // Detect "#define QT_NO_KEYWORDS" and "#define QT_NO_KEYWORDS 1", but exclude
- // "#define QT_NO_KEYWORDS_FOO"
- languageFeatures.qtKeywordsEnabled = nextChar != '\n' && nextChar != ' ';
- }
+ languageFeatures.qtKeywordsEnabled = !Utils::contains(
+ projectMacros,
+ [] (const ProjectExplorer::Macro &macro) { return macro.key == "QT_NO_KEYWORDS"; });
}
}
diff --git a/src/plugins/cpptools/projectpart.h b/src/plugins/cpptools/projectpart.h
index c04a18c61f..a6851e001d 100644
--- a/src/plugins/cpptools/projectpart.h
+++ b/src/plugins/cpptools/projectpart.h
@@ -31,6 +31,7 @@
#include "projectpartheaderpath.h"
#include <projectexplorer/projectexplorer_global.h>
+#include <projectexplorer/projectmacro.h>
#include <coreplugin/id.h>
@@ -118,7 +119,7 @@ public:
QStringList precompiledHeaders;
ProjectPartHeaderPaths headerPaths;
- QByteArray projectDefines;
+ ProjectExplorer::Macros projectMacros;
LanguageVersion languageVersion = LatestCxxVersion;
LanguageExtensions languageExtensions = NoExtensions;
@@ -130,7 +131,7 @@ public:
Core::Id toolchainType;
bool isMsvc2015Toolchain = false;
- QByteArray toolchainDefines;
+ ProjectExplorer::Macros toolChainMacros;
ToolChainWordWidth toolChainWordWidth = WordWidth32Bit;
QString toolChainTargetTriple;
};
diff --git a/src/plugins/nim/project/nimtoolchain.cpp b/src/plugins/nim/project/nimtoolchain.cpp
index 6c8fd0f32b..3605b5bcb6 100644
--- a/src/plugins/nim/project/nimtoolchain.cpp
+++ b/src/plugins/nim/project/nimtoolchain.cpp
@@ -82,9 +82,9 @@ ToolChain::PredefinedMacrosRunner NimToolChain::createPredefinedMacrosRunner() c
return ToolChain::PredefinedMacrosRunner();
}
-QByteArray NimToolChain::predefinedMacros(const QStringList &) const
+Macros NimToolChain::predefinedMacros(const QStringList &) const
{
- return QByteArray();
+ return Macros();
}
ToolChain::CompilerFlags NimToolChain::compilerFlags(const QStringList &) const
diff --git a/src/plugins/nim/project/nimtoolchain.h b/src/plugins/nim/project/nimtoolchain.h
index 7061a9751b..2da07dd2e2 100644
--- a/src/plugins/nim/project/nimtoolchain.h
+++ b/src/plugins/nim/project/nimtoolchain.h
@@ -41,7 +41,7 @@ public:
bool isValid() const override;
PredefinedMacrosRunner createPredefinedMacrosRunner() const override;
- QByteArray predefinedMacros(const QStringList &flags) const final;
+ ProjectExplorer::Macros predefinedMacros(const QStringList &flags) const final;
CompilerFlags compilerFlags(const QStringList &flags) const final;
ProjectExplorer::WarningFlags warningFlags(const QStringList &flags) const final;
diff --git a/src/plugins/projectexplorer/abstractmsvctoolchain.cpp b/src/plugins/projectexplorer/abstractmsvctoolchain.cpp
index 121e2b43b4..44d961ba08 100644
--- a/src/plugins/projectexplorer/abstractmsvctoolchain.cpp
+++ b/src/plugins/projectexplorer/abstractmsvctoolchain.cpp
@@ -118,7 +118,7 @@ ToolChain::PredefinedMacrosRunner AbstractMsvcToolChain::createPredefinedMacrosR
};
}
-QByteArray AbstractMsvcToolChain::predefinedMacros(const QStringList &cxxflags) const
+ProjectExplorer::Macros AbstractMsvcToolChain::predefinedMacros(const QStringList &cxxflags) const
{
return createPredefinedMacrosRunner()(cxxflags);
}
@@ -277,13 +277,6 @@ bool AbstractMsvcToolChain::canClone() const
return true;
}
-// Function must be thread-safe!
-QByteArray AbstractMsvcToolChain::msvcPredefinedMacros(const QStringList,
- const Utils::Environment&) const
-{
- return QByteArray();
-}
-
bool AbstractMsvcToolChain::generateEnvironmentSettings(const Utils::Environment &env,
const QString &batchFile,
const QString &batchArgs,
diff --git a/src/plugins/projectexplorer/abstractmsvctoolchain.h b/src/plugins/projectexplorer/abstractmsvctoolchain.h
index 9a96faea0e..0851e09cc0 100644
--- a/src/plugins/projectexplorer/abstractmsvctoolchain.h
+++ b/src/plugins/projectexplorer/abstractmsvctoolchain.h
@@ -53,7 +53,7 @@ public:
QString originalTargetTriple() const override;
PredefinedMacrosRunner createPredefinedMacrosRunner() const override;
- QByteArray predefinedMacros(const QStringList &cxxflags) const override;
+ Macros predefinedMacros(const QStringList &cxxflags) const override;
CompilerFlags compilerFlags(const QStringList &cxxflags) const override;
WarningFlags warningFlags(const QStringList &cflags) const override;
SystemHeaderPathsRunner createSystemHeaderPathsRunner() const override;
@@ -92,13 +92,14 @@ protected:
static void inferWarningsForLevel(int warningLevel, WarningFlags &flags);
virtual Utils::Environment readEnvironmentSetting(const Utils::Environment& env) const = 0;
- virtual QByteArray msvcPredefinedMacros(const QStringList cxxflags,
- const Utils::Environment& env) const;
+ // Function must be thread-safe!
+ virtual Macros msvcPredefinedMacros(const QStringList cxxflags,
+ const Utils::Environment& env) const = 0;
Utils::FileName m_debuggerCommand;
mutable QMutex *m_predefinedMacrosMutex = nullptr;
- mutable QByteArray m_predefinedMacros;
+ mutable Macros 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;
diff --git a/src/plugins/projectexplorer/customtoolchain.cpp b/src/plugins/projectexplorer/customtoolchain.cpp
index 06a3b041e8..dc0989eed1 100644
--- a/src/plugins/projectexplorer/customtoolchain.cpp
+++ b/src/plugins/projectexplorer/customtoolchain.cpp
@@ -32,6 +32,7 @@
#include "customparser.h"
#include "customparserconfigdialog.h"
#include "projectexplorerconstants.h"
+#include "projectmacro.h"
#include "toolchainmanager.h"
#include <utils/algorithm.h>
@@ -118,39 +119,24 @@ bool CustomToolChain::isValid() const
ToolChain::PredefinedMacrosRunner CustomToolChain::createPredefinedMacrosRunner() const
{
- const QStringList theMacros = m_predefinedMacros;
+ const Macros theMacros = m_predefinedMacros;
// This runner must be thread-safe!
return [theMacros](const QStringList &cxxflags){
QByteArray result;
- QStringList macros = theMacros;
+ Macros macros = theMacros;
for (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);
- }
- }
- }
- for (const QString &str : Utils::asConst(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';
- }
+ if (cxxFlag.startsWith(QLatin1String("-D")))
+ macros.append(Macro::fromKeyValue(cxxFlag.mid(2).trimmed()));
+ else if (cxxFlag.startsWith(QLatin1String("-U")) && !cxxFlag.contains('='))
+ macros.append({cxxFlag.mid(2).trimmed().toUtf8(), MacroType::Undefine});
+
}
- return result;
+ return macros;
};
}
-QByteArray CustomToolChain::predefinedMacros(const QStringList &cxxflags) const
+Macros CustomToolChain::predefinedMacros(const QStringList &cxxflags) const
{
return createPredefinedMacrosRunner()(cxxflags);
}
@@ -169,16 +155,16 @@ WarningFlags CustomToolChain::warningFlags(const QStringList &cxxflags) const
return WarningFlags::Default;
}
-const QStringList &CustomToolChain::rawPredefinedMacros() const
+const Macros &CustomToolChain::rawPredefinedMacros() const
{
return m_predefinedMacros;
}
-void CustomToolChain::setPredefinedMacros(const QStringList &list)
+void CustomToolChain::setPredefinedMacros(const Macros &macros)
{
- if (m_predefinedMacros == list)
+ if (m_predefinedMacros == macros)
return;
- m_predefinedMacros = list;
+ m_predefinedMacros = macros;
toolChainUpdated();
}
@@ -323,7 +309,8 @@ QVariantMap CustomToolChain::toMap() const
data.insert(QLatin1String(compilerCommandKeyC), m_compilerCommand.toString());
data.insert(QLatin1String(makeCommandKeyC), m_makeCommand.toString());
data.insert(QLatin1String(targetAbiKeyC), m_targetAbi.toString());
- data.insert(QLatin1String(predefinedMacrosKeyC), m_predefinedMacros);
+ QStringList macros = Utils::transform<QList>(m_predefinedMacros, [](const Macro &m) { return QString::fromUtf8(m.toByteArray()); });
+ data.insert(QLatin1String(predefinedMacrosKeyC), macros);
data.insert(QLatin1String(headerPathsKeyC), headerPathsList());
data.insert(QLatin1String(cxx11FlagsKeyC), m_cxx11Flags);
data.insert(QLatin1String(mkspecsKeyC), mkspecs());
@@ -352,7 +339,8 @@ bool CustomToolChain::fromMap(const QVariantMap &data)
m_compilerCommand = FileName::fromString(data.value(QLatin1String(compilerCommandKeyC)).toString());
m_makeCommand = FileName::fromString(data.value(QLatin1String(makeCommandKeyC)).toString());
m_targetAbi = Abi(data.value(QLatin1String(targetAbiKeyC)).toString());
- m_predefinedMacros = data.value(QLatin1String(predefinedMacrosKeyC)).toStringList();
+ const QStringList macros = data.value(QLatin1String(predefinedMacrosKeyC)).toStringList();
+ m_predefinedMacros = Macro::toMacros(macros.join('\n').toUtf8());
setHeaderPaths(data.value(QLatin1String(headerPathsKeyC)).toStringList());
m_cxx11Flags = data.value(QLatin1String(cxx11FlagsKeyC)).toStringList();
setMkspecs(data.value(QLatin1String(mkspecsKeyC)).toString());
@@ -526,11 +514,16 @@ public:
return static_cast<QPlainTextEdit *>(widget());
}
- inline QStringList entries() const
+ QStringList entries() const
{
return textEditWidget()->toPlainText().split(QLatin1Char('\n'), QString::SkipEmptyParts);
}
+ QString text() const
+ {
+ return textEditWidget()->toPlainText();
+ }
+
// not accurate, counts empty lines (except last)
int entryCount() const
{
@@ -656,7 +649,7 @@ void CustomToolChainConfigWidget::applyImpl()
tc->setCompilerCommand(m_compilerCommand->fileName());
tc->setMakeCommand(m_makeCommand->fileName());
tc->setTargetAbi(m_abiWidget->currentAbi());
- tc->setPredefinedMacros(m_predefinedDetails->entries());
+ tc->setPredefinedMacros(Macro::toMacros(m_predefinedDetails->text().toUtf8()));
tc->setHeaderPaths(m_headerDetails->entries());
tc->setCxx11Flags(m_cxx11Flags->text().split(QLatin1Char(',')));
tc->setMkspecs(m_mkspecs->text());
@@ -673,8 +666,8 @@ void CustomToolChainConfigWidget::setFromToolchain()
m_compilerCommand->setFileName(tc->compilerCommand());
m_makeCommand->setFileName(FileName::fromString(tc->makeCommand(Environment())));
m_abiWidget->setAbis(QList<Abi>(), tc->targetAbi());
- m_predefinedMacros->setPlainText(tc->rawPredefinedMacros().join(QLatin1Char('\n')));
- m_headerPaths->setPlainText(tc->headerPathsList().join(QLatin1Char('\n')));
+ m_predefinedMacros->setPlainText(QString::fromUtf8(Macro::toByteArray(tc->rawPredefinedMacros())));
+ m_headerPaths->setPlainText(tc->headerPathsList().join('\n'));
m_cxx11Flags->setText(tc->cxx11Flags().join(QLatin1Char(',')));
m_mkspecs->setText(tc->mkspecs());
int index = m_errorParserComboBox->findData(tc->outputParserId().toSetting());
@@ -690,7 +683,7 @@ bool CustomToolChainConfigWidget::isDirtyImpl() const
return m_compilerCommand->fileName() != tc->compilerCommand()
|| m_makeCommand->path() != tc->makeCommand(Environment())
|| m_abiWidget->currentAbi() != tc->targetAbi()
- || m_predefinedDetails->entries() != tc->rawPredefinedMacros()
+ || Macro::toMacros(m_predefinedDetails->text().toUtf8()) != tc->rawPredefinedMacros()
|| m_headerDetails->entries() != tc->headerPathsList()
|| m_cxx11Flags->text().split(QLatin1Char(',')) != tc->cxx11Flags()
|| m_mkspecs->text() != tc->mkspecs()
diff --git a/src/plugins/projectexplorer/customtoolchain.h b/src/plugins/projectexplorer/customtoolchain.h
index fa5ec68ed0..75ba190c66 100644
--- a/src/plugins/projectexplorer/customtoolchain.h
+++ b/src/plugins/projectexplorer/customtoolchain.h
@@ -72,11 +72,11 @@ public:
bool isValid() const override;
PredefinedMacrosRunner createPredefinedMacrosRunner() const override;
- QByteArray predefinedMacros(const QStringList &cxxflags) const override;
+ Macros 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);
+ const Macros &rawPredefinedMacros() const;
+ void setPredefinedMacros(const Macros &macros);
SystemHeaderPathsRunner createSystemHeaderPathsRunner() const override;
QList<HeaderPath> systemHeaderPaths(const QStringList &cxxFlags,
@@ -124,7 +124,7 @@ private:
Utils::FileName m_makeCommand;
Abi m_targetAbi;
- QStringList m_predefinedMacros;
+ Macros m_predefinedMacros;
QList<HeaderPath> m_systemHeaderPaths;
QStringList m_cxx11Flags;
Utils::FileNameList m_mkspecs;
diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp
index 102441bdf1..9800908a53 100644
--- a/src/plugins/projectexplorer/gcctoolchain.cpp
+++ b/src/plugins/projectexplorer/gcctoolchain.cpp
@@ -28,6 +28,7 @@
#include "gcctoolchainfactories.h"
#include "gccparser.h"
#include "linuxiccparser.h"
+#include "projectmacro.h"
#include "projectexplorerconstants.h"
#include "toolchainmanager.h"
@@ -48,6 +49,7 @@
#include <QLineEdit>
#include <QRegularExpression>
+#include <algorithm>
#include <memory>
using namespace Utils;
@@ -119,6 +121,11 @@ HeaderPathsCache::Cache HeaderPathsCache::cache() const
return m_cache;
}
+MacroCache::MacroCache() : m_mutex(QMutex::Recursive)
+{
+ m_cache.reserve(CACHE_SIZE + 1);
+}
+
MacroCache::MacroCache(const MacroCache &other)
: MacroCache()
{
@@ -126,40 +133,21 @@ MacroCache::MacroCache(const MacroCache &other)
m_cache = other.cache();
}
-void MacroCache::insert(const QStringList &compilerCommand, const QByteArray &macros)
+void MacroCache::insert(const QStringList &compilerCommand, const Macros &macros)
{
- if (macros.isNull())
+ QMutexLocker locker(&m_mutex);
+ if (macros.isEmpty() || unlockedCheck(compilerCommand).isEmpty())
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();
- }
+ m_cache.push_back(qMakePair(compilerCommand, macros));
+ if (m_cache.size() > CACHE_SIZE)
+ m_cache.pop_front();
}
-QByteArray MacroCache::check(const QStringList &compilerCommand) const
+Macros 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();
+ return unlockedCheck(compilerCommand);
}
MacroCache::Cache MacroCache::cache() const
@@ -168,6 +156,16 @@ MacroCache::Cache MacroCache::cache() const
return m_cache;
}
+Macros MacroCache::unlockedCheck(const QStringList &compilerCommand) const
+{
+ auto it = std::stable_partition(m_cache.begin(), m_cache.end(), [&](const CacheItem &ci) {
+ return ci.first == compilerCommand;
+ });
+ if (it != m_cache.end())
+ return it->second;
+ return {};
+}
+
static QByteArray runGcc(const FileName &gcc, const QStringList &arguments, const QStringList &env)
{
if (gcc.isEmpty() || !gcc.toFileInfo().isExecutable())
@@ -196,25 +194,28 @@ static const QStringList gccPredefinedMacrosOptions(Core::Id languageId)
return QStringList({langOption, "-E", "-dM"});
}
-static QByteArray gccPredefinedMacros(const FileName &gcc, const QStringList &args, const QStringList &env)
+static ProjectExplorer::Macros gccPredefinedMacros(const FileName &gcc,
+ const QStringList &args,
+ const QStringList &env)
{
QStringList arguments = args;
arguments << "-";
- QByteArray predefinedMacros = runGcc(gcc, arguments, env);
+ ProjectExplorer::Macros predefinedMacros = Macro::toMacros(runGcc(gcc, arguments, env));
// Sanity check in case we get an error message instead of real output:
- QTC_CHECK(predefinedMacros.isNull() || predefinedMacros.startsWith("#define "));
+ QTC_CHECK(predefinedMacros.isEmpty()
+ || predefinedMacros.front().type == ProjectExplorer::MacroType::Define);
if (HostOsInfo::isMacHost()) {
// Turn off flag indicating Apple's blocks support
- const QByteArray blocksDefine("#define __BLOCKS__ 1");
- const QByteArray blocksUndefine("#undef __BLOCKS__");
+ const ProjectExplorer::Macro blocksDefine("__BLOCKS__", "1");
+ const ProjectExplorer::Macro blocksUndefine("__BLOCKS__", ProjectExplorer::MacroType::Undefine);
const int idx = predefinedMacros.indexOf(blocksDefine);
if (idx != -1)
- predefinedMacros.replace(idx, blocksDefine.length(), blocksUndefine);
+ predefinedMacros[idx] = blocksUndefine;
// Define __strong and __weak (used for Apple's GC extension of C) to be empty
- predefinedMacros.append("#define __strong\n");
- predefinedMacros.append("#define __weak\n");
+ predefinedMacros.append({"__strong"});
+ predefinedMacros.append({"__weak"});
}
return predefinedMacros;
}
@@ -261,7 +262,7 @@ QList<HeaderPath> GccToolChain::gccHeaderPaths(const FileName &gcc, const QStrin
return systemHeaderPaths;
}
-static QList<Abi> guessGccAbi(const QString &m, const QByteArray &macros)
+static QList<Abi> guessGccAbi(const QString &m, const ProjectExplorer::Macros &macros)
{
QList<Abi> abiList;
@@ -274,19 +275,13 @@ static QList<Abi> guessGccAbi(const QString &m, const QByteArray &macros)
Abi::OSFlavor flavor = guessed.osFlavor();
Abi::BinaryFormat format = guessed.binaryFormat();
int width = guessed.wordWidth();
- const QByteArray mscVer = "#define _MSC_VER ";
-
- if (macros.contains("#define __SIZEOF_SIZE_T__ 8"))
- width = 64;
- else if (macros.contains("#define __SIZEOF_SIZE_T__ 4"))
- width = 32;
- else if (macros.contains("#define __SIZEOF_SIZE_T__ 2"))
- width = 16;
- int mscVerIndex = macros.indexOf(mscVer);
- if (mscVerIndex != -1) {
- mscVerIndex += mscVer.length();
- const int eol = macros.indexOf('\n', mscVerIndex);
- const int msvcVersion = macros.mid(mscVerIndex, eol - mscVerIndex).toInt();
+
+ const Macro sizeOfMacro = Utils::findOrDefault(macros, [](const Macro &m) { return m.key == "__SIZEOF_SIZE_T__"; });
+ if (sizeOfMacro.isValid() && sizeOfMacro.type == MacroType::Define)
+ width = sizeOfMacro.value.toInt() * 8;
+ const Macro &mscVerMacro = Utils::findOrDefault(macros, [](const Macro &m) { return m.key == "_MSC_VER"; });
+ if (mscVerMacro.type == MacroType::Define) {
+ const int msvcVersion = mscVerMacro.value.toInt();
flavor = Abi::flavorForMsvcVersion(msvcVersion);
}
@@ -305,7 +300,7 @@ static QList<Abi> guessGccAbi(const QString &m, const QByteArray &macros)
static GccToolChain::DetectedAbisResult guessGccAbi(const FileName &path, const QStringList &env,
- const QByteArray &macros,
+ const ProjectExplorer::Macros &macros,
const QStringList &extraArgs = QStringList())
{
if (path.isEmpty())
@@ -495,8 +490,8 @@ ToolChain::PredefinedMacrosRunner GccToolChain::createPredefinedMacrosRunner() c
}
arguments = reinterpretOptions(arguments);
- QByteArray macros = macroCache->check(arguments);
- if (!macros.isNull())
+ Macros macros = macroCache->check(arguments);
+ if (!macros.isEmpty())
return macros;
macros = gccPredefinedMacros(findLocalCompiler(compilerCommand, env),
@@ -517,7 +512,7 @@ ToolChain::PredefinedMacrosRunner GccToolChain::createPredefinedMacrosRunner() c
* adds _OPENMP macro, for full list of macro search by word "when" on this page:
* http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
*/
-QByteArray GccToolChain::predefinedMacros(const QStringList &cxxflags) const
+ProjectExplorer::Macros GccToolChain::predefinedMacros(const QStringList &cxxflags) const
{
return createPredefinedMacrosRunner()(cxxflags);
}
@@ -701,6 +696,8 @@ void GccToolChain::addCommandPathToEnvironment(const FileName &command, Environm
env.prependOrSetPath(command.parentDir().toString());
}
+GccToolChain::GccToolChain(const GccToolChain &) = default;
+
void GccToolChain::addToEnvironment(Environment &env) const
{
addCommandPathToEnvironment(m_compilerCommand, env);
@@ -898,7 +895,7 @@ GccToolChain::DetectedAbisResult GccToolChain::detectSupportedAbis() const
{
Environment env = Environment::systemEnvironment();
addToEnvironment(env);
- QByteArray macros = predefinedMacros(QStringList());
+ ProjectExplorer::Macros macros = predefinedMacros(QStringList());
return guessGccAbi(findLocalCompiler(m_compilerCommand, env),
env.toStringList(),
macros,
@@ -1060,7 +1057,7 @@ QList<ToolChain *> GccToolChainFactory::autoDetectToolChain(const FileName &comp
Environment systemEnvironment = Environment::systemEnvironment();
GccToolChain::addCommandPathToEnvironment(compilerPath, systemEnvironment);
const FileName localCompilerPath = findLocalCompiler(compilerPath, systemEnvironment);
- QByteArray macros
+ Macros macros
= gccPredefinedMacros(localCompilerPath, gccPredefinedMacrosOptions(language),
systemEnvironment.toStringList());
const GccToolChain::DetectedAbisResult detectedAbis = guessGccAbi(localCompilerPath,
@@ -1765,7 +1762,7 @@ void ProjectExplorerPlugin::testGccAbiGuessing()
QFETCH(QByteArray, macros);
QFETCH(QStringList, abiList);
- QList<Abi> al = guessGccAbi(input, macros);
+ QList<Abi> al = guessGccAbi(input, ProjectExplorer::Macro::toMacros(macros));
QCOMPARE(al.count(), abiList.count());
for (int i = 0; i < al.count(); ++i)
QCOMPARE(al.at(i).toString(), abiList.at(i));
diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h
index 0399b1ec14..a3c4b4eaca 100644
--- a/src/plugins/projectexplorer/gcctoolchain.h
+++ b/src/plugins/projectexplorer/gcctoolchain.h
@@ -51,7 +51,7 @@ class LinuxIccToolChainFactory;
// GccToolChain
// --------------------------------------------------------------------------
-class PROJECTEXPLORER_EXPORT HeaderPathsCache
+class HeaderPathsCache
{
public:
HeaderPathsCache() : m_mutex(QMutex::Recursive) {}
@@ -69,20 +69,22 @@ private:
mutable Cache m_cache;
};
-class PROJECTEXPLORER_EXPORT MacroCache
+class MacroCache
{
public:
- MacroCache() : m_mutex(QMutex::Recursive) {}
+ MacroCache();
MacroCache(const MacroCache &other);
- void insert(const QStringList &compilerCommand, const QByteArray &macros);
- QByteArray check(const QStringList &compilerCommand) const;
+ void insert(const QStringList &compilerCommand, const Macros &macros);
+ Macros check(const QStringList &compilerCommand) const;
protected:
- using CacheItem = QPair<QStringList, QByteArray>;
- using Cache = QList<CacheItem>;
+ using CacheItem = QPair<QStringList, Macros>;
+ using Cache = QVector<CacheItem>;
Cache cache() const;
private:
+ // Does not lock!
+ Macros unlockedCheck(const QStringList &compilerCommand) const;
mutable QMutex m_mutex;
mutable Cache m_cache;
};
@@ -104,7 +106,7 @@ public:
WarningFlags warningFlags(const QStringList &cflags) const override;
PredefinedMacrosRunner createPredefinedMacrosRunner() const override;
- QByteArray predefinedMacros(const QStringList &cxxflags) const override;
+ Macros predefinedMacros(const QStringList &cxxflags) const override;
SystemHeaderPathsRunner createSystemHeaderPathsRunner() const override;
QList<HeaderPath> systemHeaderPaths(const QStringList &cxxflags,
@@ -147,14 +149,16 @@ public:
};
protected:
- GccToolChain(const GccToolChain &) = default;
+ using CacheItem = QPair<QStringList, Macros>;
+ using GccCache = QVector<CacheItem>;
+
+ GccToolChain(const GccToolChain &);
void setCompilerCommand(const Utils::FileName &path);
void setSupportedAbis(const QList<Abi> &m_abis);
void setOriginalTargetTriple(const QString &targetTriple);
-
- void setMacroCache(const QStringList &allCxxflags, const QByteArray &macros) const;
- QByteArray macroCache(const QStringList &allCxxflags) const;
+ void setMacroCache(const QStringList &allCxxflags, const Macros &macroCache) const;
+ Macros macroCache(const QStringList &allCxxflags) const;
virtual QString defaultDisplayName() const;
virtual CompilerFlags defaultCompilerFlags() const;
diff --git a/src/plugins/projectexplorer/gcctoolchainfactories.h b/src/plugins/projectexplorer/gcctoolchainfactories.h
index 4417fc712f..e4c0a583e9 100644
--- a/src/plugins/projectexplorer/gcctoolchainfactories.h
+++ b/src/plugins/projectexplorer/gcctoolchainfactories.h
@@ -99,7 +99,7 @@ private:
AbiWidget *m_abiWidget;
bool m_isReadOnly = false;
- QByteArray m_macros;
+ ProjectExplorer::Macros m_macros;
};
// --------------------------------------------------------------------------
diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp
index 2562b7fcc4..2ff34dbcb8 100644
--- a/src/plugins/projectexplorer/msvctoolchain.cpp
+++ b/src/plugins/projectexplorer/msvctoolchain.cpp
@@ -410,31 +410,18 @@ static QByteArray msvcCompilationFile()
//
// [1] https://msdn.microsoft.com/en-us/library/b0084kay.aspx
// [2] http://stackoverflow.com/questions/3665537/how-to-find-out-cl-exes-built-in-macros
-QByteArray MsvcToolChain::msvcPredefinedMacros(const QStringList cxxflags,
- const Utils::Environment &env) const
+Macros MsvcToolChain::msvcPredefinedMacros(const QStringList cxxflags,
+ const Utils::Environment &env) const
{
- QByteArray predefinedMacros;
+ Macros predefinedMacros;
QStringList toProcess;
- foreach (const QString &arg, cxxflags) {
+ for (const QString &arg : cxxflags) {
if (arg.startsWith(QLatin1String("/D"))) {
- QString define = arg.mid(2);
- int pos = define.indexOf(QLatin1Char('='));
- if (pos < 0) {
- predefinedMacros += "#define ";
- predefinedMacros += define.toLocal8Bit();
- predefinedMacros += '\n';
- } else {
- predefinedMacros += "#define ";
- predefinedMacros += define.left(pos).toLocal8Bit();
- predefinedMacros += ' ';
- predefinedMacros += define.mid(pos + 1).toLocal8Bit();
- predefinedMacros += '\n';
- }
+ const QString define = arg.mid(2);
+ predefinedMacros.append(Macro::fromKeyValue(define));
} else if (arg.startsWith(QLatin1String("/U"))) {
- predefinedMacros += "#undef ";
- predefinedMacros += arg.mid(2).toLocal8Bit();
- predefinedMacros += '\n';
+ predefinedMacros.append({arg.mid(2).toLocal8Bit(), ProjectExplorer::MacroType::Undefine});
} else if (arg.startsWith(QLatin1String("-I"))) {
// Include paths should not have any effect on defines
} else {
@@ -468,18 +455,8 @@ QByteArray MsvcToolChain::msvcPredefinedMacros(const QStringList cxxflags,
const QStringList output = Utils::filtered(response.stdOut().split('\n'),
[](const QString &s) { return s.startsWith('V'); });
- foreach (const QString& line, output) {
- QStringList split = line.split('=');
- const QString key = split.at(0).mid(1);
- QString value = split.at(1);
- predefinedMacros += "#define ";
- predefinedMacros += key.toUtf8();
- predefinedMacros += ' ';
- predefinedMacros += value.toUtf8();
- predefinedMacros += '\n';
- }
- if (debug)
- qDebug() << "msvcPredefinedMacros" << predefinedMacros;
+ for (const QString &line : output)
+ predefinedMacros.append(Macro::fromKeyValue(line.mid(1)));
return predefinedMacros;
}
diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h
index fd341177eb..3dcb715286 100644
--- a/src/plugins/projectexplorer/msvctoolchain.h
+++ b/src/plugins/projectexplorer/msvctoolchain.h
@@ -82,8 +82,8 @@ protected:
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;
+ Macros msvcPredefinedMacros(const QStringList cxxflags,
+ const Utils::Environment &env) const override;
private:
QList<Utils::EnvironmentItem> environmentModifications() const;
diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro
index d702d3a120..979a3e865d 100644
--- a/src/plugins/projectexplorer/projectexplorer.pro
+++ b/src/plugins/projectexplorer/projectexplorer.pro
@@ -149,7 +149,8 @@ HEADERS += projectexplorer.h \
projectexplorer_global.h \
extracompiler.h \
customexecutableconfigurationwidget.h \
- customexecutablerunconfiguration.h
+ customexecutablerunconfiguration.h \
+ projectmacro.h
SOURCES += projectexplorer.cpp \
abi.cpp \
@@ -284,7 +285,8 @@ SOURCES += projectexplorer.cpp \
projectexplorericons.cpp \
extracompiler.cpp \
customexecutableconfigurationwidget.cpp \
- customexecutablerunconfiguration.cpp
+ customexecutablerunconfiguration.cpp \
+ projectmacro.cpp
FORMS += processstep.ui \
editorsettingspropertiespage.ui \
diff --git a/src/plugins/projectexplorer/projectexplorerunittestfiles.pri b/src/plugins/projectexplorer/projectexplorerunittestfiles.pri
new file mode 100644
index 0000000000..6b005059e6
--- /dev/null
+++ b/src/plugins/projectexplorer/projectexplorerunittestfiles.pri
@@ -0,0 +1,12 @@
+shared {
+ DEFINES += PROJECTEXPLORER_LIBRARY
+} else {
+ DEFINES += PROJECTEXPLORER_STATIC_LIBRARY
+}
+
+HEADERS += \
+ $$PWD/projectmacro.h
+
+SOURCES += \
+ $$PWD/projectmacro.cpp
+
diff --git a/src/plugins/projectexplorer/projectmacro.cpp b/src/plugins/projectexplorer/projectmacro.cpp
new file mode 100644
index 0000000000..e69e60421d
--- /dev/null
+++ b/src/plugins/projectexplorer/projectmacro.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** 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 "projectmacro.h"
+
+#include <utils/algorithm.h>
+
+namespace ProjectExplorer {
+
+bool Macro::isValid() const
+{
+ return !key.isEmpty() && type != MacroType::Invalid;
+}
+
+QByteArray Macro::toByteArray() const
+{
+ switch (type) {
+ case MacroType::Define: return QByteArray("#define ") + key + ' ' + value;
+ case MacroType::Undefine: return QByteArray("#undef ") + key;
+ case MacroType::Invalid: break;
+ }
+
+ return QByteArray();
+}
+
+QByteArray Macro::toByteArray(const Macros &macros)
+{
+ QByteArray text;
+
+ for (const Macro &macro : macros) {
+ const QByteArray macroText = macro.toByteArray();
+ if (!macroText.isEmpty())
+ text += macroText + '\n';
+ }
+
+ return text;
+}
+
+QByteArray Macro::toByteArray(const QVector<Macros> &macrosVector)
+{
+ QByteArray text;
+
+ for (const Macros &macros : macrosVector)
+ text += toByteArray(macros);
+
+ return text;
+}
+
+Macros Macro::toMacros(const QByteArray &text)
+{
+ return tokensLinesToMacros(tokenizeLines(splitLines(text)));
+}
+
+Macro Macro::fromKeyValue(const QString &utf16text)
+{
+ return fromKeyValue(utf16text.toUtf8());
+}
+
+Macro Macro::fromKeyValue(const QByteArray &text)
+{
+ QByteArray key;
+ QByteArray value;
+ MacroType type = MacroType::Invalid;
+
+ if (!text.isEmpty()) {
+ type = MacroType::Define;
+
+ int index = text.indexOf('=');
+
+ if (index != -1) {
+ key = text.left(index).trimmed();
+ value = text.mid(index + 1).trimmed();
+ } else {
+ key = text.trimmed();
+ value = "1";
+ }
+ }
+
+ return Macro(key, value, type);
+}
+
+QByteArray Macro::toKeyValue(const QByteArray &prefix) const
+{
+ QByteArray keyValue;
+ if (type != MacroType::Invalid)
+ keyValue = prefix;
+
+ if (value.isEmpty())
+ keyValue += key;
+ else
+ keyValue += key + '=' + value;
+
+ return keyValue;
+}
+
+static void removeCarriageReturn(QByteArray &line)
+{
+ if (line.endsWith('\r'))
+ line.truncate(line.size() - 1);
+}
+
+static void removeCarriageReturns(QList<QByteArray> &lines)
+{
+ for (QByteArray &line : lines)
+ removeCarriageReturn(line);
+}
+
+QList<QByteArray> Macro::splitLines(const QByteArray &text)
+{
+ QList<QByteArray> splitLines = text.split('\n');
+
+ splitLines.removeAll("");
+ removeCarriageReturns(splitLines);
+
+ return splitLines;
+}
+
+QByteArray Macro::removeNonsemanticSpaces(QByteArray line)
+{
+ auto begin = line.begin();
+ auto end = line.end();
+ bool notInString = true;
+
+ auto newEnd = std::unique(begin, end, [&] (char first, char second) {
+ notInString = notInString && first != '\"';
+ return notInString && (first == '#' || std::isspace(first)) && std::isspace(second);
+ });
+
+ line.truncate(line.size() - int(std::distance(newEnd, end)));
+
+ return line.trimmed();
+}
+
+QList<QByteArray> Macro::tokenizeLine(const QByteArray &line)
+{
+ const QByteArray normalizedLine = removeNonsemanticSpaces(line);
+
+ const auto begin = normalizedLine.begin();
+ auto first = std::find(normalizedLine.begin(), normalizedLine.end(), ' ');
+ auto second = std::find(std::next(first), normalizedLine.end(), ' ');
+ const auto end = normalizedLine.end();
+
+ QList<QByteArray> tokens;
+
+ if (first != end) {
+ tokens.append(QByteArray(begin, int(std::distance(begin, first))));
+
+ std::advance(first, 1);
+ tokens.append(QByteArray(first, int(std::distance(first, second))));
+
+ if (second != end) {
+ std::advance(second, 1);
+ tokens.append(QByteArray(second, int(std::distance(second, end))));
+ }
+ }
+
+ return tokens;
+}
+
+QList<QList<QByteArray>> Macro::tokenizeLines(const QList<QByteArray> &lines)
+{
+ QList<QList<QByteArray>> tokensLines = Utils::transform(lines, &Macro::tokenizeLine);
+
+ return tokensLines;
+}
+
+Macro Macro::tokensToMacro(const QList<QByteArray> &tokens)
+{
+ Macro macro;
+
+ if (tokens.size() >= 2 && tokens[0] == "#define") {
+ macro.type = MacroType::Define;
+ macro.key = tokens[1];
+
+ if (tokens.size() >= 3)
+ macro.value = tokens[2];
+ }
+
+ return macro;
+}
+
+Macros Macro::tokensLinesToMacros(const QList<QList<QByteArray>> &tokensLines)
+{
+ Macros macros;
+ macros.reserve(tokensLines.size());
+
+ for (const QList<QByteArray> &tokens : tokensLines) {
+ Macro macro = tokensToMacro(tokens);
+
+ if (macro.type != MacroType::Invalid)
+ macros.push_back(std::move(macro));
+ }
+
+ return macros;
+}
+
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/projectmacro.h b/src/plugins/projectexplorer/projectmacro.h
new file mode 100644
index 0000000000..9489b54d80
--- /dev/null
+++ b/src/plugins/projectexplorer/projectmacro.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** 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 "projectexplorer_export.h"
+
+#include <QByteArray>
+#include <QHash>
+#include <QVector>
+
+namespace ProjectExplorer {
+
+enum class MacroType
+{
+ Invalid,
+ Define,
+ Undefine
+};
+
+class Macro;
+
+using Macros = QVector<Macro>;
+
+class PROJECTEXPLORER_EXPORT Macro
+{
+public:
+ Macro() = default;
+
+ Macro(QByteArray key, QByteArray value, MacroType type = MacroType::Define)
+ : key(key), value(value), type(type)
+ {}
+
+ Macro(QByteArray key, MacroType type = MacroType::Define)
+ : key(key), type(type)
+ {}
+
+ bool isValid() const;
+
+ QByteArray toByteArray() const;
+ static QByteArray toByteArray(const Macros &macros);
+ static QByteArray toByteArray(const QVector<Macros> &macross);
+
+ static Macros toMacros(const QByteArray &text);
+
+ // define Foo will be converted to Foo=1
+ static Macro fromKeyValue(const QString &utf16text);
+ static Macro fromKeyValue(const QByteArray &text);
+ QByteArray toKeyValue(const QByteArray &prefix) const;
+
+public:
+ QByteArray key;
+ QByteArray value;
+ MacroType type = MacroType::Invalid;
+
+private:
+ static QList<QByteArray> splitLines(const QByteArray &text);
+ static QByteArray removeNonsemanticSpaces(QByteArray line);
+ static QList<QByteArray> tokenizeLine(const QByteArray &line);
+ static QList<QList<QByteArray>> tokenizeLines(const QList<QByteArray> &lines);
+ static Macro tokensToMacro(const QList<QByteArray> &tokens);
+ static Macros tokensLinesToMacros(const QList<QList<QByteArray>> &tokensLines);
+};
+
+inline
+uint qHash(const Macro &macro)
+{
+ using ::qHash;
+ return qHash(macro.key) ^ qHash(macro.value) ^ qHash(int(macro.type));
+}
+
+inline
+bool operator==(const Macro &first, const Macro &second)
+{
+ return first.type == second.type
+ && first.key == second.key
+ && first.value == second.value;
+}
+
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h
index 8c461bd398..4ee56f05a8 100644
--- a/src/plugins/projectexplorer/toolchain.h
+++ b/src/plugins/projectexplorer/toolchain.h
@@ -27,6 +27,7 @@
#include "projectexplorer_export.h"
#include "projectexplorer_global.h"
+#include "projectmacro.h"
#include <coreplugin/id.h>
@@ -122,9 +123,9 @@ public:
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<QByteArray(const QStringList &cxxflags)>;
+ using PredefinedMacrosRunner = std::function<Macros(const QStringList &cxxflags)>;
virtual PredefinedMacrosRunner createPredefinedMacrosRunner() const = 0;
- virtual QByteArray predefinedMacros(const QStringList &cxxflags) const = 0;
+ virtual Macros predefinedMacros(const QStringList &cxxflags) const = 0;
// A SystemHeaderPathsRunner is created in the ui thread and runs in another thread.
using SystemHeaderPathsRunner = std::function<QList<HeaderPath>(const QStringList &cxxflags, const QString &sysRoot)>;
diff --git a/src/plugins/projectexplorer/toolchainmanager.cpp b/src/plugins/projectexplorer/toolchainmanager.cpp
index df7d6888ec..b6c79b8773 100644
--- a/src/plugins/projectexplorer/toolchainmanager.cpp
+++ b/src/plugins/projectexplorer/toolchainmanager.cpp
@@ -492,7 +492,7 @@ public:
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(); }
+ Macros predefinedMacros(const QStringList &cxxflags) const override { Q_UNUSED(cxxflags); return Macros(); }
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(); }
diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp
index 11e035a0e7..902bed93f0 100644
--- a/src/plugins/qbsprojectmanager/qbsproject.cpp
+++ b/src/plugins/qbsprojectmanager/qbsproject.cpp
@@ -975,17 +975,7 @@ void QbsProject::updateCppCodeModel()
QStringList list = props.getModulePropertiesAsStringList(
QLatin1String(CONFIG_CPP_MODULE),
QLatin1String(CONFIG_DEFINES));
- QByteArray grpDefines;
- foreach (const QString &def, list) {
- QByteArray data = def.toUtf8();
- int pos = data.indexOf('=');
- if (pos >= 0)
- data[pos] = ' ';
- else
- data.append(" 1"); // cpp.defines: [ "FOO" ] is considered to be "FOO=1"
- grpDefines += (QByteArray("#define ") + data + '\n');
- }
- rpp.setDefines(grpDefines);
+ rpp.setMacros(Utils::transform<QVector>(list, [](const QString &s) { return ProjectExplorer::Macro::fromKeyValue(s); }));
list = props.getModulePropertiesAsStringList(QLatin1String(CONFIG_CPP_MODULE),
QLatin1String(CONFIG_INCLUDEPATHS));
diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp
index 0d4703b15d..f53192e016 100644
--- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp
@@ -292,7 +292,7 @@ void QmakeProject::updateCppCodeModel()
rpp.setBuildSystemTarget(pro->targetInformation().target);
// TODO: Handle QMAKE_CFLAGS
rpp.setFlagsForCxx({cxxToolChain, pro->variableValue(Variable::CppFlags)});
- rpp.setDefines(pro->cxxDefines());
+ rpp.setMacros(ProjectExplorer::Macro::toMacros(pro->cxxDefines()));
rpp.setPreCompiledHeaders(pro->variableValue(Variable::PrecompiledHeader));
rpp.setSelectedForBuilding(pro->includedInExactParse());
diff --git a/tests/unit/mockup/projectexplorer/toolchain.h b/tests/unit/mockup/projectexplorer/toolchain.h
index 33bfa836df..9bcf43a59b 100644
--- a/tests/unit/mockup/projectexplorer/toolchain.h
+++ b/tests/unit/mockup/projectexplorer/toolchain.h
@@ -27,6 +27,7 @@
#include <projectexplorer/headerpath.h>
#include <projectexplorer/abi.h>
+#include <projectexplorer/projectmacro.h>
#include <coreplugin/id.h>
#include <functional>
@@ -59,7 +60,7 @@ public:
using SystemHeaderPathsRunner = std::function<QList<HeaderPath>(const QStringList &cxxflags, const QString &sysRoot)>;
virtual SystemHeaderPathsRunner createSystemHeaderPathsRunner() const { return SystemHeaderPathsRunner(); }
- using PredefinedMacrosRunner = std::function<QByteArray(const QStringList &cxxflags)>;
+ using PredefinedMacrosRunner = std::function<Macros(const QStringList &cxxflags)>;
virtual PredefinedMacrosRunner createPredefinedMacrosRunner() const { return PredefinedMacrosRunner(); }
virtual QString originalTargetTriple() const { return QString(); }
diff --git a/tests/unit/unittest/creator_dependency.pri b/tests/unit/unittest/creator_dependency.pri
index edf7417029..b9a5db097c 100644
--- a/tests/unit/unittest/creator_dependency.pri
+++ b/tests/unit/unittest/creator_dependency.pri
@@ -7,13 +7,13 @@ include($$PWD/../../../src/libs/utils/utils-lib.pri)
include($$PWD/../../../src/libs/sqlite/sqlite-lib.pri)
include($$PWD/../../../src/libs/clangsupport/clangsupport-lib.pri)
include($$PWD/../../../src/plugins/coreplugin/corepluginunittestfiles.pri)
+include($$PWD/../../../src/plugins/projectexplorer/projectexplorerunittestfiles.pri)
include($$PWD/../../../src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri)
include($$PWD/../../../src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri)
include($$PWD/../../../src/plugins/clangrefactoring/clangrefactoring-source.pri)
include($$PWD/../../../src/plugins/clangpchmanager/clangpchmanager-source.pri)
include($$PWD/../../../src/plugins/cpptools/cpptoolsunittestfiles.pri)
include(cplusplus.pri)
-
!isEmpty(LLVM_INSTALL_DIR) {
include($$PWD/../../../src/shared/clang/clang_defines.pri)
include($$PWD/../../../src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri)
diff --git a/tests/unit/unittest/google-using-declarations.h b/tests/unit/unittest/google-using-declarations.h
index 4a04cec394..7a1fe3b30f 100644
--- a/tests/unit/unittest/google-using-declarations.h
+++ b/tests/unit/unittest/google-using-declarations.h
@@ -43,4 +43,5 @@ using testing::Property;
using testing::Return;
using testing::ReturnRef;
using testing::Sequence;
+using testing::StrEq;
using testing::UnorderedElementsAre;
diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp
index 5980ec6c63..d7cb22b7ce 100644
--- a/tests/unit/unittest/gtest-creator-printing.cpp
+++ b/tests/unit/unittest/gtest-creator-printing.cpp
@@ -29,6 +29,8 @@
#include <coreplugin/find/searchresultitem.h>
+#include <projectexplorer/projectmacro.h>
+
namespace Core {
namespace Search {
@@ -54,3 +56,35 @@ void PrintTo(const TextRange &range, ::std::ostream *os)
}
}
+
+namespace ProjectExplorer {
+
+static const char *typeToString(const MacroType &type)
+{
+ switch (type) {
+ case MacroType::Invalid: return "MacroType::Invalid";
+ case MacroType::Define: return "MacroType::Define";
+ case MacroType::Undefine: return "MacroType::Undefine";
+ }
+
+ return "";
+}
+
+std::ostream &operator<<(std::ostream &out, const MacroType &type)
+{
+ out << typeToString(type);
+
+ return out;
+}
+
+std::ostream &operator<<(std::ostream &out, const Macro &macro)
+{
+ out << "("
+ << macro.key.data() << ", "
+ << macro.value.data() << ", "
+ << macro.type << ")";
+
+ return out;
+}
+
+}
diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h
index 814130f227..92db70f6ed 100644
--- a/tests/unit/unittest/gtest-creator-printing.h
+++ b/tests/unit/unittest/gtest-creator-printing.h
@@ -42,3 +42,13 @@ void PrintTo(const TextRange &range, ::std::ostream *os);
}
}
+
+namespace ProjectExplorer {
+
+enum class MacroType;
+class Macro;
+
+std::ostream &operator<<(std::ostream &out, const MacroType &type);
+std::ostream &operator<<(std::ostream &out, const Macro &macro);
+
+}
diff --git a/tests/unit/unittest/projectmacro-test.cpp b/tests/unit/unittest/projectmacro-test.cpp
new file mode 100644
index 0000000000..2c9258e635
--- /dev/null
+++ b/tests/unit/unittest/projectmacro-test.cpp
@@ -0,0 +1,408 @@
+/****************************************************************************
+**
+** 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"
+
+#define private public
+#include <projectexplorer/projectmacro.h>
+#undef private
+
+namespace {
+
+using ProjectExplorer::MacroType;
+using ProjectExplorer::Macro;
+using ProjectExplorer::Macros;
+
+MATCHER_P3(IsMacro, key, value, type,
+ std::string(negation ? "isn't" : "is")
+ + " key "+ PrintToString(key)
+ + ", value " + PrintToString(value)
+ + " and type " + PrintToString(type))
+{
+ return arg.key == key && arg.value == value && arg.type == type;
+}
+
+TEST(Macro, SplitLines)
+{
+ QByteArray text = "#define Foo 42\n\n#define Bar\n#define HoHoHo Bar\n// foo";
+
+ auto textLines = Macro::splitLines(text);
+
+ ASSERT_THAT(textLines, ElementsAre("#define Foo 42", "#define Bar", "#define HoHoHo Bar", "// foo"));
+}
+
+TEST(Macro, RemoveCarriageReturn)
+{
+ QByteArray text = "#define Foo 42\r\n#define Bar\n";
+
+ auto textLines = Macro::splitLines(text);
+
+ ASSERT_THAT(textLines, ElementsAre("#define Foo 42", "#define Bar"));
+}
+
+TEST(Macro, TokenizeNullLine)
+{
+ QByteArray line;
+
+ auto tokens = Macro::tokenizeLine(line);
+
+ ASSERT_THAT(tokens, IsEmpty());
+}
+
+TEST(Macro, TokenizeEmptyLine)
+{
+ QByteArray line = "";
+
+ auto tokens = Macro::tokenizeLine(line);
+
+ ASSERT_THAT(tokens, IsEmpty());
+}
+
+TEST(Macro, TokenizeSpaces)
+{
+ QByteArray line = " ";
+
+ auto tokens = Macro::tokenizeLine(line);
+
+ ASSERT_THAT(tokens, IsEmpty());
+}
+
+TEST(Macro, TokenizeOneEntry)
+{
+ QByteArray line = "//blah";
+
+ auto tokens = Macro::tokenizeLine(line);
+
+ ASSERT_THAT(tokens, IsEmpty());
+}
+
+TEST(Macro, TokenizeThreeEntries)
+{
+ QByteArray line = "#define Foo 42";
+
+ auto tokens = Macro::tokenizeLine(line);
+
+ ASSERT_THAT(tokens, ElementsAre("#define", "Foo", "42"));
+}
+
+TEST(Macro, TokenizeManyEntries)
+{
+ QByteArray line = "#define Foo unsigned long long int";
+
+ auto tokens = Macro::tokenizeLine(line);
+
+ ASSERT_THAT(tokens, ElementsAre("#define", "Foo", "unsigned long long int"));
+}
+
+TEST(Macro, TokenizeWithMutipleSpaces)
+{
+ QByteArray line = "#define Foo 42";
+
+ auto tokens = Macro::tokenizeLine(line);
+
+ ASSERT_THAT(tokens, ElementsAre("#define", "Foo", "42"));
+}
+
+TEST(Macro, TokenizeLines)
+{
+ QList<QByteArray> lines = {"#define Foo 42",
+ "#define Bar Ho",
+ "// this is a comment",
+ " "};
+
+ auto tokensLines = Macro::tokenizeLines(lines);
+
+ ASSERT_THAT(tokensLines,
+ ElementsAre(ElementsAre("#define", "Foo", "42"),
+ ElementsAre("#define", "Bar", "Ho"),
+ ElementsAre("//", "this", "is a comment"),
+ IsEmpty()));
+}
+
+TEST(Macro, SpacesBeforEntries)
+{
+ QByteArray line = " #define Foo";
+
+ auto strippedLine = Macro::removeNonsemanticSpaces(line);
+
+ ASSERT_THAT(strippedLine, "#define Foo");
+}
+
+TEST(Macro, SpacesAfterEntries)
+{
+ QByteArray line = "#define Foo ";
+
+ auto strippedLine = Macro::removeNonsemanticSpaces(line);
+
+ ASSERT_THAT(strippedLine, "#define Foo");
+}
+
+TEST(Macro, ManySpacesInbetweenEntries)
+{
+ QByteArray line = "#define \t Foo 42";
+
+ auto strippedLine = Macro::removeNonsemanticSpaces(line);
+
+ ASSERT_THAT(strippedLine, "#define Foo 42");
+}
+
+TEST(Macro, EmptyString)
+{
+ QByteArray line = "#define \t Foo \"\"";
+
+ auto strippedLine = Macro::removeNonsemanticSpaces(line);
+
+ ASSERT_THAT(strippedLine, "#define Foo \"\"");
+}
+
+TEST(Macro, StringWithQuotes)
+{
+ QByteArray line = "#define \t Foo \"\\\"string\\\"\"";
+
+ auto strippedLine = Macro::removeNonsemanticSpaces(line);
+
+ ASSERT_THAT(strippedLine, "#define Foo \"\\\"string\\\"\"");
+}
+
+TEST(Macro, DISABLED_StringConcatenation)
+{
+ QByteArray line = "#define \t Foo \"a\" \"b\"";
+
+ auto strippedLine = Macro::removeNonsemanticSpaces(line);
+
+ ASSERT_THAT(strippedLine, "#define Foo \"a\" \"b\"");
+}
+
+TEST(Macro, DISABLED_TokenConcatenation)
+{
+ QByteArray line = "#define \t Foo \"a\" ## c";
+
+ auto strippedLine = Macro::removeNonsemanticSpaces(line);
+
+ ASSERT_THAT(strippedLine, "#define Foo \"a\" ## c");
+}
+
+TEST(Macro, StringWithQuotesAndSpaces)
+{
+ QByteArray line = "#define \t Foo \"\\\"string \\\"\"";
+
+ auto strippedLine = Macro::removeNonsemanticSpaces(line);
+
+ ASSERT_THAT(strippedLine.toStdString(), "#define Foo \"\\\"string \\\"\"");
+}
+
+TEST(Macro, SpacesAferHashEntries)
+{
+ QByteArray line = "# define Foo 42";
+
+ auto strippedLine = Macro::removeNonsemanticSpaces(line);
+
+ ASSERT_THAT(strippedLine, "#define Foo 42");
+}
+
+TEST(Macro, SpacesInStringEntries)
+{
+ QByteArray line = "#define Foo \"some text with spaces\"";
+
+ auto strippedLine = Macro::removeNonsemanticSpaces(line);
+
+ ASSERT_THAT(strippedLine, "#define Foo \"some text with spaces\"");
+}
+
+TEST(Macro, EmptyTokensToMacro)
+{
+ QList<QByteArray> tokens;
+
+ auto macro = Macro::tokensToMacro(tokens);
+
+ ASSERT_THAT(macro, IsMacro("", "", MacroType::Invalid));
+}
+
+TEST(Macro, DefineTwoTokensToMacro)
+{
+ QList<QByteArray> tokens = {"#define", "Foo"};
+
+ auto macro = Macro::tokensToMacro(tokens);
+
+ ASSERT_THAT(macro, IsMacro("Foo", "", MacroType::Define));
+}
+
+TEST(Macro, DefineThreeTokensToMacro)
+{
+ QList<QByteArray> tokens = {"#define", "Foo", "42"};
+
+ auto macro = Macro::tokensToMacro(tokens);
+
+ ASSERT_THAT(macro, IsMacro("Foo", "42", MacroType::Define));
+}
+
+TEST(Macro, DoNotParseNonDefines)
+{
+ QList<QByteArray> tokens = {"//", "this", "is a comment"};
+
+ auto macro = Macro::tokensToMacro(tokens);
+
+ ASSERT_THAT(macro, IsMacro("", "", MacroType::Invalid));
+}
+
+TEST(Macro, TokensLinesToMacros)
+{
+ QList<QList<QByteArray>> tokensLines = {{"#define", "Foo", "42"},
+ {"#define", "Bar", "Ho"},
+ {"//", "this", "is", "a", "comment"},
+ {}};
+
+ auto macros = Macro::tokensLinesToMacros(tokensLines);
+
+ ASSERT_THAT(macros, ElementsAre(IsMacro("Foo", "42", MacroType::Define),
+ IsMacro("Bar", "Ho", MacroType::Define)));
+}
+
+
+TEST(Macro, TextToMacros)
+{
+ QByteArray text = {"#define Foo 42\n"
+ "#define Bar Ho\n"
+ "// this is a comment\n"
+ " "};
+
+ auto macros = Macro::toMacros(text);
+
+ ASSERT_THAT(macros, ElementsAre(IsMacro("Foo", "42", MacroType::Define),
+ IsMacro("Bar", "Ho", MacroType::Define)));
+}
+
+TEST(Macro, InvalidToText)
+{
+ Macro macro;
+
+ auto text = macro.toByteArray();
+
+ ASSERT_THAT(text, QByteArray());
+}
+
+TEST(Macro, DefineToText)
+{
+ Macro macro{"Foo", "Bar", MacroType::Define};
+
+ auto text = macro.toByteArray();
+
+ ASSERT_THAT(text, "#define Foo Bar");
+}
+
+TEST(Macro, DefineWithSpacesToText)
+{
+ Macro macro{"LongInt", "long long int", MacroType::Define};
+
+ auto text = macro.toByteArray();
+
+ ASSERT_THAT(text, "#define LongInt long long int");
+}
+
+TEST(Macro, UndefineToText)
+{
+ Macro macro{"Foo", "Bar", MacroType::Undefine};
+
+ auto text = macro.toByteArray();
+
+ ASSERT_THAT(text, "#undef Foo");
+}
+
+TEST(Macro, MacrosToText)
+{
+ Macros macros{{"LongInt", "long long int"}, {"Foo", "Bar"}, {}};
+
+ auto text = Macro::toByteArray(macros);
+
+ ASSERT_THAT(text, "#define LongInt long long int\n#define Foo Bar\n");
+}
+
+TEST(Macro, MacrosVectorToText)
+{
+ Macros macros{{"LongInt", "long long int"}, {"Foo", "Bar"}, {}, {"Foo", MacroType::Undefine}};
+
+ auto text = Macro::toByteArray(macros);
+
+ ASSERT_THAT(text, "#define LongInt long long int\n#define Foo Bar\n#undef Foo\n");
+}
+
+TEST(Macro, EmptyKeyValueToMacro)
+{
+ QString text;
+
+ auto macro = Macro::fromKeyValue(text);
+
+ ASSERT_THAT(macro, IsMacro("", "", MacroType::Invalid));
+}
+
+TEST(Macro, KeyToMacro)
+{
+ QString text = "Foo";
+
+ auto macro = Macro::fromKeyValue(text);
+
+ ASSERT_THAT(macro, IsMacro("Foo", "1", MacroType::Define));
+}
+
+TEST(Macro, KeyValueToMacro)
+{
+ QString text = "Foo=\"Some=Text\"";
+
+ auto macro = Macro::fromKeyValue(text);
+
+ ASSERT_THAT(macro, IsMacro("Foo", "\"Some=Text\"", MacroType::Define));
+}
+
+TEST(Macro, InvalidMacroToKeyValue)
+{
+ Macro macro;
+ QByteArray prefix = "-D";
+
+ auto keyValue = macro.toKeyValue(prefix);
+
+ ASSERT_THAT(keyValue, "");
+}
+
+TEST(Macro, DefineKeyOnlyMacroToKeyValue)
+{
+ Macro macro{"Foo"};
+ QByteArray prefix = "-D";
+
+ auto keyValue = macro.toKeyValue(prefix);
+
+ ASSERT_THAT(keyValue, "-DFoo");
+}
+
+TEST(Macro, DefineMacroToKeyValue)
+{
+ Macro macro{"Foo", "Bar"};
+ QByteArray prefix = "-D";
+
+ auto keyValue = macro.toKeyValue(prefix);
+
+ ASSERT_THAT(keyValue, "-DFoo=Bar");
+}
+}
+
diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro
index 1f1b490536..e4f2c363c0 100644
--- a/tests/unit/unittest/unittest.pro
+++ b/tests/unit/unittest/unittest.pro
@@ -37,7 +37,6 @@ DEFINES += CPPTOOLS_JSON=\"R\\\"xxx($${cpptoolsjson.output})xxx\\\"\"
SOURCES += \
changedfilepathcompressor-test.cpp \
- clangfollowsymbol-test.cpp \
clangpathwatcher-test.cpp \
clangqueryexamplehighlightmarker-test.cpp \
clangqueryhighlightmarker-test.cpp \
@@ -59,6 +58,7 @@ SOURCES += \
pchmanagerclient-test.cpp \
pchmanagerserver-test.cpp \
processevents-utilities.cpp \
+ projectmacro-test.cpp \
projectparts-test.cpp \
projectupdater-test.cpp \
readandwritemessageblock-test.cpp \
@@ -96,6 +96,7 @@ SOURCES += \
clangdocumentsuspenderresumer-test.cpp \
clangdocument-test.cpp \
clangfixitoperation-test.cpp \
+ clangfollowsymbol-test.cpp \
clangisdiagnosticrelatedtolocation-test.cpp \
clangjobqueue-test.cpp \
clangjobs-test.cpp \