CompilerOptionsBuilder unit-tests

Bonus: minor compiler options builder issues fixed.

Change-Id: Ie25f8fad6729339de05f2bf9b614ceac873e2634
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-09-26 14:10:35 +02:00
parent e79d68dab6
commit f6e5202b80
7 changed files with 380 additions and 28 deletions

View File

@@ -170,11 +170,6 @@ void CompilerOptionsBuilder::add(const QString &option)
m_options.append(option);
}
void CompilerOptionsBuilder::addDefine(const ProjectExplorer::Macro &macro)
{
m_options.append(defineDirectiveToDefineOption(macro));
}
void CompilerOptionsBuilder::addWordWidth()
{
const QString argument = m_projectPart.toolChainWordWidth == ProjectPart::WordWidth64Bit
@@ -211,7 +206,7 @@ static QString creatorResourcePath()
#ifndef UNIT_TESTS
return Core::ICore::resourcePath();
#else
return QString();
return QDir::toNativeSeparators(QString::fromUtf8(QTC_RESOURCE_DIR ""));
#endif
}
@@ -221,7 +216,7 @@ static QString clangIncludeDirectory(const QString &clangVersion,
#ifndef UNIT_TESTS
return Core::ICore::clangIncludeDirectory(clangVersion, clangResourceDirectory);
#else
return QString();
return QDir::toNativeSeparators(QString::fromUtf8(CLANG_RESOURCE_DIR ""));
#endif
}
@@ -238,12 +233,20 @@ static int lastIncludeIndex(const QStringList &options, const QRegularExpression
return index;
}
static int includeIndexForResourceDirectory(const QStringList &options)
static int includeIndexForResourceDirectory(const QStringList &options, bool isMacOs = false)
{
// include/c++/{version}, include/c++/v1 and include/g++
const int cppIncludeIndex = lastIncludeIndex(
options,
QRegularExpression("\\A.*[\\/\\\\]include[\\/\\\\].*(g\\+\\+.*\\z|c\\+\\+[\\/\\\\](v1\\z|\\d+.*\\z))"));
static const QRegularExpression includeRegExp(
R"(\A.*[\/\\]include[\/\\].*(g\+\+.*\z|c\+\+[\/\\](v1\z|\d+.*\z)))");
// The same as includeRegExp but also matches /usr/local/include
static const QRegularExpression includeRegExpMac(
R"(\A(.*[\/\\]include[\/\\].*(g\+\+.*\z|c\+\+[\/\\](v1\z|\d+.*\z))))"
R"(|([\/\\]usr[\/\\]local[\/\\]include\z))");
const int cppIncludeIndex = lastIncludeIndex(options, isMacOs
? includeRegExpMac
: includeRegExp);
if (cppIncludeIndex > 0)
return cppIncludeIndex + 1;
@@ -317,7 +320,8 @@ void CompilerOptionsBuilder::addHeaderPathOptions()
const QString clangIncludePath
= clangIncludeDirectory(m_clangVersion, m_clangResourceDirectory);
int includeIndexForResourceDir = includeIndexForResourceDirectory(builtInIncludes);
int includeIndexForResourceDir = includeIndexForResourceDirectory(
builtInIncludes, m_projectPart.toolChainTargetTriple.contains("darwin"));
if (includeIndexForResourceDir >= 0) {
builtInIncludes.insert(includeIndexForResourceDir, clangIncludePath);

View File

@@ -56,33 +56,27 @@ public:
SkipBuiltIn skipBuiltInHeaderPathsAndDefines = SkipBuiltIn::No,
QString clangVersion = QString(),
QString clangResourceDirectory = QString());
virtual ~CompilerOptionsBuilder() {}
virtual void addTargetTriple();
virtual void addExtraCodeModelFlags();
virtual void enableExceptions();
virtual void insertWrappedQtHeaders();
virtual void addOptionsForLanguage(bool checkForBorlandExtensions = true);
virtual void updateLanguageOption(ProjectFile::Kind fileKind);
virtual void addExtraOptions() {}
QStringList build(ProjectFile::Kind fileKind,
PchUsage pchUsage);
QStringList options() const;
// Add custom options
void add(const QString &option);
void addDefine(const ProjectExplorer::Macro &marco);
virtual void addExtraOptions() {}
// Add options based on project part
virtual void addToolchainAndProjectMacros();
void addWordWidth();
void addToolchainFlags();
void addHeaderPathOptions();
void addPrecompiledHeaderOptions(PchUsage pchUsage);
virtual void addToolchainAndProjectMacros();
void addMacros(const ProjectExplorer::Macros &macros);
void addTargetTriple();
void addExtraCodeModelFlags();
void enableExceptions();
void insertWrappedQtHeaders();
void addOptionsForLanguage(bool checkForBorlandExtensions = true);
void updateLanguageOption(ProjectFile::Kind fileKind);
void addMsvcCompatibilityVersion();
void undefineCppLanguageFeatureMacrosForMsvc2015();
void addDefineFunctionMacrosMsvc();
@@ -97,8 +91,13 @@ protected:
virtual QString defineOption() const;
virtual QString undefineOption() const;
virtual QString includeOption() const;
// Add custom options
void add(const QString &option);
QString includeDirOptionForPath(const QString &path) const;
const ProjectPart m_projectPart;
const ProjectPart &m_projectPart;
private:
QByteArray macroOption(const ProjectExplorer::Macro &macro) const;

View File

@@ -33,6 +33,8 @@ namespace ProjectExplorer {
class Project : public QObject {
public:
Project() = default;
Utils::FileName projectDirectory() const {
return Utils::FileName();
}

View File

@@ -1,4 +1,6 @@
include(../../../src/shared/clang/clang_installation.pri)
include(../../../src/shared/clang/clang_defines.pri)
!isEmpty(LLVM_VERSION) {
requires(!isEmpty(LIBCLANG_LIBS))
equals(LLVM_IS_COMPILED_WITH_RTTI, "NO") : message("LLVM needs to be compiled with RTTI!")

View File

@@ -0,0 +1,343 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "googletest.h"
#include <cpptools/compileroptionsbuilder.h>
#include <cpptools/cppprojectfile.h>
#include <cpptools/projectpart.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorerconstants.h>
using CppTools::CompilerOptionsBuilder;
using CppTools::ProjectFile;
using CppTools::ProjectPart;
using ProjectExplorer::HeaderPath;
using ProjectExplorer::HeaderPathType;
using ProjectExplorer::Project;
MATCHER_P(IsPartOfHeader, headerPart, std::string(negation ? "isn't " : "is ") + headerPart)
{
return arg.contains(QString::fromUtf8(headerPart));
}
class CompilerOptionsBuilderTest : public ::testing::Test
{
protected:
void SetUp() final
{
projectPart.project = project.get();
projectPart.toolchainType = ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID;
projectPart.languageVersion = CppTools::ProjectPart::CXX17;
projectPart.toolChainWordWidth = CppTools::ProjectPart::WordWidth64Bit;
projectPart.toolChainTargetTriple = "x86_64-apple-darwin10";
projectPart.extraCodeModelFlags = QStringList{"-arch", "x86_64"};
projectPart.precompiledHeaders = QStringList{TESTDATA_DIR "/compileroptionsbuilder.pch"};
projectPart.toolChainMacros = {ProjectExplorer::Macro{"foo", "bar"}};
projectPart.projectMacros = {ProjectExplorer::Macro{"projectFoo", "projectBar"}};
projectPart.qtVersion = ProjectPart::Qt5;
projectPart.headerPaths = {HeaderPath{"/tmp/builtin_path", HeaderPathType::BuiltIn},
HeaderPath{"/tmp/system_path", HeaderPathType::System},
HeaderPath{"/tmp/path", HeaderPathType::User}};
}
std::unique_ptr<Project> project{std::make_unique<ProjectExplorer::Project>()};
ProjectPart projectPart;
CompilerOptionsBuilder compilerOptionsBuilder{projectPart};
};
TEST_F(CompilerOptionsBuilderTest, AddToolchainAndProjectMacros)
{
compilerOptionsBuilder.addToolchainAndProjectMacros();
ASSERT_THAT(compilerOptionsBuilder.options(), ElementsAre("-Dfoo=bar", "-DprojectFoo=projectBar"));
}
TEST_F(CompilerOptionsBuilderTest, AddWordWidth)
{
compilerOptionsBuilder.addWordWidth();
ASSERT_THAT(compilerOptionsBuilder.options(), ElementsAre("-m64"));
}
TEST_F(CompilerOptionsBuilderTest, AddToolchainFlags)
{
compilerOptionsBuilder.addToolchainFlags();
ASSERT_THAT(compilerOptionsBuilder.options(), ElementsAre("-undef"));
}
TEST_F(CompilerOptionsBuilderTest, HeaderPathOptionsOrder)
{
compilerOptionsBuilder.addHeaderPathOptions();
ASSERT_THAT(compilerOptionsBuilder.options(),
ElementsAre("-nostdlibinc",
"-I", QDir::toNativeSeparators("/tmp/path"),
"-I", QDir::toNativeSeparators("/tmp/system_path"),
"-isystem", QDir::toNativeSeparators("/tmp/builtin_path")));
}
TEST_F(CompilerOptionsBuilderTest, UseSystemHeader)
{
CompilerOptionsBuilder compilerOptionsBuilder(projectPart, CppTools::UseSystemHeader::Yes);
compilerOptionsBuilder.addHeaderPathOptions();
ASSERT_THAT(compilerOptionsBuilder.options(),
ElementsAre("-nostdlibinc",
"-I", QDir::toNativeSeparators("/tmp/path"),
"-isystem", QDir::toNativeSeparators("/tmp/system_path"),
"-isystem", QDir::toNativeSeparators("/tmp/builtin_path")));
}
TEST_F(CompilerOptionsBuilderTest, ClangHeadersPath)
{
CompilerOptionsBuilder compilerOptionsBuilder(projectPart,
CppTools::UseSystemHeader::No,
CppTools::SkipBuiltIn::No,
"7.0.0",
"");
compilerOptionsBuilder.addHeaderPathOptions();
ASSERT_THAT(compilerOptionsBuilder.options(),
ElementsAre("-nostdinc",
"-nostdlibinc",
"-I", QDir::toNativeSeparators("/tmp/path"),
"-I", QDir::toNativeSeparators("/tmp/system_path"),
"-isystem", QDir::toNativeSeparators(CLANG_RESOURCE_DIR ""),
"-isystem", QDir::toNativeSeparators("/tmp/builtin_path")));
}
TEST_F(CompilerOptionsBuilderTest, ClangHeadersAndCppIncludesPathsOrderMacOs)
{
auto defaultPaths = projectPart.headerPaths;
projectPart.headerPaths = {HeaderPath{"/usr/include/c++/4.2.1", HeaderPathType::BuiltIn},
HeaderPath{"/usr/include/c++/4.2.1/backward", HeaderPathType::BuiltIn},
HeaderPath{"/usr/local/include", HeaderPathType::BuiltIn},
HeaderPath{"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0/include", HeaderPathType::BuiltIn},
HeaderPath{"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include", HeaderPathType::BuiltIn},
HeaderPath{"/usr/include", HeaderPathType::BuiltIn}
};
projectPart.headerPaths.append(defaultPaths);
CompilerOptionsBuilder compilerOptionsBuilder(projectPart,
CppTools::UseSystemHeader::No,
CppTools::SkipBuiltIn::No,
"7.0.0",
"");
compilerOptionsBuilder.addHeaderPathOptions();
ASSERT_THAT(compilerOptionsBuilder.options(),
ElementsAre("-nostdinc",
"-nostdlibinc",
"-I", QDir::toNativeSeparators("/tmp/path"),
"-I", QDir::toNativeSeparators("/tmp/system_path"),
"-isystem", QDir::toNativeSeparators("/usr/include/c++/4.2.1"),
"-isystem", QDir::toNativeSeparators("/usr/include/c++/4.2.1/backward"),
"-isystem", QDir::toNativeSeparators("/usr/local/include"),
"-isystem", QDir::toNativeSeparators(CLANG_RESOURCE_DIR ""),
"-isystem", QDir::toNativeSeparators("/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include"),
"-isystem", QDir::toNativeSeparators("/usr/include"),
"-isystem", QDir::toNativeSeparators("/tmp/builtin_path")));
}
TEST_F(CompilerOptionsBuilderTest, ClangHeadersAndCppIncludesPathsOrderLinux)
{
projectPart.headerPaths = {HeaderPath{"/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8", HeaderPathType::BuiltIn},
HeaderPath{"/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/backward", HeaderPathType::BuiltIn},
HeaderPath{"/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/x86_64-linux-gnu/c++/4.8", HeaderPathType::BuiltIn},
HeaderPath{"/usr/local/include", HeaderPathType::BuiltIn},
HeaderPath{"/usr/lib/gcc/x86_64-linux-gnu/4.8/include", HeaderPathType::BuiltIn},
HeaderPath{"/usr/include/x86_64-linux-gnu", HeaderPathType::BuiltIn},
HeaderPath{"/usr/include", HeaderPathType::BuiltIn}
};
projectPart.toolChainTargetTriple = "x86_64-linux-gnu";
CompilerOptionsBuilder compilerOptionsBuilder(projectPart,
CppTools::UseSystemHeader::No,
CppTools::SkipBuiltIn::No,
"7.0.0",
"");
compilerOptionsBuilder.addHeaderPathOptions();
ASSERT_THAT(compilerOptionsBuilder.options(),
ElementsAre("-nostdinc",
"-nostdlibinc",
"-isystem", QDir::toNativeSeparators("/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8"),
"-isystem", QDir::toNativeSeparators("/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/backward"),
"-isystem", QDir::toNativeSeparators("/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/x86_64-linux-gnu/c++/4.8"),
"-isystem", QDir::toNativeSeparators(CLANG_RESOURCE_DIR ""),
"-isystem", QDir::toNativeSeparators("/usr/local/include"),
"-isystem", QDir::toNativeSeparators("/usr/lib/gcc/x86_64-linux-gnu/4.8/include"),
"-isystem", QDir::toNativeSeparators("/usr/include/x86_64-linux-gnu"),
"-isystem", QDir::toNativeSeparators("/usr/include")));
}
TEST_F(CompilerOptionsBuilderTest, NoPrecompiledHeader)
{
compilerOptionsBuilder.addPrecompiledHeaderOptions(CompilerOptionsBuilder::PchUsage::None);
ASSERT_THAT(compilerOptionsBuilder.options().empty(), true);
}
TEST_F(CompilerOptionsBuilderTest, UsePrecompiledHeader)
{
compilerOptionsBuilder.addPrecompiledHeaderOptions(CompilerOptionsBuilder::PchUsage::Use);
ASSERT_THAT(compilerOptionsBuilder.options(),
ElementsAre("-include", QDir::toNativeSeparators(TESTDATA_DIR "/compileroptionsbuilder.pch")));
}
TEST_F(CompilerOptionsBuilderTest, AddMacros)
{
compilerOptionsBuilder.addMacros(ProjectExplorer::Macros{ProjectExplorer::Macro{"key", "value"}});
ASSERT_THAT(compilerOptionsBuilder.options(), ElementsAre("-Dkey=value"));
}
TEST_F(CompilerOptionsBuilderTest, AddTargetTriple)
{
compilerOptionsBuilder.addTargetTriple();
ASSERT_THAT(compilerOptionsBuilder.options(), ElementsAre("-target", "x86_64-apple-darwin10"));
}
TEST_F(CompilerOptionsBuilderTest, EnableCExceptions)
{
projectPart.languageVersion = CppTools::ProjectPart::C99;
compilerOptionsBuilder.enableExceptions();
ASSERT_THAT(compilerOptionsBuilder.options(), ElementsAre("-fexceptions"));
}
TEST_F(CompilerOptionsBuilderTest, EnableCXXExceptions)
{
compilerOptionsBuilder.enableExceptions();
ASSERT_THAT(compilerOptionsBuilder.options(), ElementsAre("-fcxx-exceptions", "-fexceptions"));
}
TEST_F(CompilerOptionsBuilderTest, InsertWrappedQtHeaders)
{
compilerOptionsBuilder.insertWrappedQtHeaders();
ASSERT_THAT(compilerOptionsBuilder.options(), Contains(IsPartOfHeader("wrappedQtHeaders")));
}
TEST_F(CompilerOptionsBuilderTest, SetLanguageVersion)
{
compilerOptionsBuilder.updateLanguageOption(ProjectFile::CXXSource);
ASSERT_THAT(compilerOptionsBuilder.options(), ElementsAre("-x", "c++"));
}
TEST_F(CompilerOptionsBuilderTest, HandleLanguageExtension)
{
projectPart.languageExtensions = ProjectPart::ObjectiveCExtensions;
compilerOptionsBuilder.updateLanguageOption(ProjectFile::CXXSource);
ASSERT_THAT(compilerOptionsBuilder.options(), ElementsAre("-x", "objective-c++"));
}
TEST_F(CompilerOptionsBuilderTest, UpdateLanguageVersion)
{
compilerOptionsBuilder.updateLanguageOption(ProjectFile::CXXSource);
compilerOptionsBuilder.updateLanguageOption(ProjectFile::CXXHeader);
ASSERT_THAT(compilerOptionsBuilder.options(), ElementsAre("-x", "c++-header"));
}
TEST_F(CompilerOptionsBuilderTest, AddMsvcCompatibilityVersion)
{
projectPart.toolchainType = ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID;
projectPart.toolChainMacros.append(ProjectExplorer::Macro{"_MSC_FULL_VER", "190000000"});
compilerOptionsBuilder.addMsvcCompatibilityVersion();
ASSERT_THAT(compilerOptionsBuilder.options(), ElementsAre("-fms-compatibility-version=19.00"));
}
TEST_F(CompilerOptionsBuilderTest, UndefineCppLanguageFeatureMacrosForMsvc2015)
{
projectPart.toolchainType = ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID;
projectPart.isMsvc2015Toolchain = true;
compilerOptionsBuilder.undefineCppLanguageFeatureMacrosForMsvc2015();
ASSERT_THAT(compilerOptionsBuilder.options(), Contains(QString{"-U__cpp_aggregate_bases"}));
}
TEST_F(CompilerOptionsBuilderTest, AddDefineFunctionMacrosMsvc)
{
projectPart.toolchainType = ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID;
compilerOptionsBuilder.addDefineFunctionMacrosMsvc();
ASSERT_THAT(compilerOptionsBuilder.options(), Contains(QString{"-D__FUNCTION__=\"\""}));
}
TEST_F(CompilerOptionsBuilderTest, AddProjectConfigFileInclude)
{
projectPart.projectConfigFile = "dummy_file.h";
compilerOptionsBuilder.addProjectConfigFileInclude();
ASSERT_THAT(compilerOptionsBuilder.options(), ElementsAre("-include", "dummy_file.h"));
}
TEST_F(CompilerOptionsBuilderTest, UndefineClangVersionMacrosForMsvc)
{
projectPart.toolchainType = ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID;
compilerOptionsBuilder.undefineClangVersionMacrosForMsvc();
ASSERT_THAT(compilerOptionsBuilder.options(), Contains(QString{"-U__clang__"}));
}
TEST_F(CompilerOptionsBuilderTest, BuildAllOptions)
{
compilerOptionsBuilder.build(ProjectFile::CXXSource, CompilerOptionsBuilder::PchUsage::None);
ASSERT_THAT(compilerOptionsBuilder.options(),
ElementsAre(
"-nostdlibinc", "-c", "-m64", "-target", "x86_64-apple-darwin10",
"-arch", "x86_64", "-x", "c++", "-std=c++17", "-fcxx-exceptions",
"-fexceptions", "-Dfoo=bar", "-DprojectFoo=projectBar", "-undef",
"-I", QDir::toNativeSeparators("D:/code/qt-creator/tests/unit/unittest/../../../share/qtcreator/cplusplus/wrappedQtHeaders"),
"-I", QDir::toNativeSeparators("D:/code/qt-creator/tests/unit/unittest/../../../share/qtcreator/cplusplus/wrappedQtHeaders/QtCore"),
"-I", QDir::toNativeSeparators("/tmp/path"),
"-I", QDir::toNativeSeparators("/tmp/system_path"),
"-isystem", QDir::toNativeSeparators("/tmp/builtin_path")
));
}

View File

@@ -20,6 +20,7 @@ DEFINES += \
QT_USE_FAST_CONCATENATION \
UNIT_TESTS \
DONT_CHECK_MESSAGE_COUNTER \
QTC_RESOURCE_DIR=\"R\\\"xxx($$PWD/../../../share/qtcreator)xxx\\\"\" \
TESTDATA_DIR=\"R\\\"xxx($$PWD/data)xxx\\\"\"
msvc: QMAKE_CXXFLAGS_WARN_ON -= -w34100 # 'unreferenced formal parameter' in MATCHER_* functions
win32:DEFINES += ECHOSERVER=\"R\\\"xxx($$OUT_PWD/../echo)xxx\\\"\"
@@ -102,6 +103,7 @@ SOURCES += \
projectpartqueue-test.cpp \
processormanager-test.cpp \
taskscheduler-test.cpp \
compileroptionsbuilder-test.cpp
!isEmpty(LIBCLANG_LIBS) {
SOURCES += \