forked from qt-creator/qt-creator
CompilationDatabase: Support both code models
Extract headers, defines and fileKind from flags in order to have complete project parts. Side-effect: better support for MSVC-specific flags. Change-Id: Iaa1413c91c96c3cf89ddbe76a7a1f0f46c5289c0 Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
@@ -26,133 +26,48 @@
|
||||
#include "compilationdatabaseproject.h"
|
||||
|
||||
#include "compilationdatabaseconstants.h"
|
||||
#include "compilationdatabaseutils.h"
|
||||
|
||||
#include <coreplugin/icontext.h>
|
||||
#include <cpptools/projectinfo.h>
|
||||
#include <cpptools/cppprojectupdater.h>
|
||||
#include <projectexplorer/gcctoolchain.h>
|
||||
#include <projectexplorer/headerpath.h>
|
||||
#include <projectexplorer/kitinformation.h>
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/projectnodes.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <projectexplorer/toolchainconfigwidget.h>
|
||||
#include <projectexplorer/toolchainmanager.h>
|
||||
#include <texteditor/textdocument.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/runextensions.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <QRegularExpression>
|
||||
#ifdef Q_OS_WIN
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
namespace CompilationDatabaseProjectManager {
|
||||
namespace Internal {
|
||||
|
||||
class DBProjectNode : public ProjectExplorer::ProjectNode
|
||||
namespace {
|
||||
class DBProjectNode : public ProjectNode
|
||||
{
|
||||
public:
|
||||
explicit DBProjectNode(const Utils::FileName &projectFilePath)
|
||||
: ProjectExplorer::ProjectNode(projectFilePath)
|
||||
: ProjectNode(projectFilePath)
|
||||
{}
|
||||
};
|
||||
|
||||
static QStringList splitCommandLine(QString commandLine)
|
||||
{
|
||||
QStringList result;
|
||||
bool insideQuotes = false;
|
||||
|
||||
// Remove escaped quotes.
|
||||
commandLine.replace("\\\"", "'");
|
||||
for (const QString &part : commandLine.split(QRegularExpression("\""))) {
|
||||
if (insideQuotes) {
|
||||
const QString quotedPart = "\"" + part + "\"";
|
||||
if (result.last().endsWith("="))
|
||||
result.last().append(quotedPart);
|
||||
else
|
||||
result.append(quotedPart);
|
||||
} else { // If 's' is outside quotes ...
|
||||
result.append(part.split(QRegularExpression("\\s+"), QString::SkipEmptyParts));
|
||||
}
|
||||
insideQuotes = !insideQuotes;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static QString updatedPathFlag(const QString &pathStr, const QString &workingDir,
|
||||
const QString &originalFlag)
|
||||
{
|
||||
QString result = pathStr;
|
||||
if (!QDir(pathStr).exists()
|
||||
&& QDir(workingDir + "/" + pathStr).exists()) {
|
||||
result = workingDir + "/" + pathStr;
|
||||
}
|
||||
|
||||
if (originalFlag.startsWith("-I"))
|
||||
return "-I" + result;
|
||||
|
||||
if (originalFlag.startsWith("-isystem"))
|
||||
return "-isystem" + result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static QStringList filteredFlags(const QStringList &flags, const QString &fileName,
|
||||
const QString &workingDir)
|
||||
{
|
||||
QStringList filtered;
|
||||
// Skip compiler call if present.
|
||||
bool skipNext = !flags.first().startsWith('-');
|
||||
bool includePath = false;
|
||||
|
||||
for (const QString &flag : flags) {
|
||||
if (skipNext) {
|
||||
skipNext = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
QString pathStr;
|
||||
if (includePath) {
|
||||
includePath = false;
|
||||
pathStr = flag;
|
||||
} else if ((flag.startsWith("-I") || flag.startsWith("-isystem"))
|
||||
&& flag != "-I" && flag != "-isystem") {
|
||||
pathStr = flag.mid(flag.startsWith("-I") ? 2 : 8);
|
||||
}
|
||||
|
||||
if (!pathStr.isEmpty()) {
|
||||
filtered.push_back(updatedPathFlag(pathStr, workingDir, flag));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flag == "-c" || flag == "-pedantic" || flag.startsWith("/") || flag.startsWith("-m")
|
||||
|| flag.startsWith("-O") || flag.startsWith("-W") || flag.startsWith("-w")
|
||||
|| flag.startsWith("--sysroot=")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flag == "-target" || flag == "-triple" || flag == "-isysroot" || flag == "-isystem"
|
||||
|| flag == "--sysroot") {
|
||||
skipNext = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flag.endsWith(fileName))
|
||||
continue;
|
||||
|
||||
if (flag == "-I" || flag == "-isystem")
|
||||
includePath = true;
|
||||
|
||||
filtered.push_back(flag);
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
static CppTools::RawProjectPart makeRawProjectPart(const Utils::FileName &projectFile,
|
||||
const QJsonObject &object,
|
||||
const QString &workingDir,
|
||||
const Utils::FileName &fileName)
|
||||
QStringList jsonObjectFlags(const QJsonObject &object)
|
||||
{
|
||||
QStringList flags;
|
||||
const QJsonArray arguments = object["arguments"].toArray();
|
||||
@@ -163,21 +78,234 @@ static CppTools::RawProjectPart makeRawProjectPart(const Utils::FileName &projec
|
||||
flags.append(arg.toString());
|
||||
}
|
||||
|
||||
flags = filteredFlags(flags, fileName.fileName(), workingDir);
|
||||
return flags;
|
||||
}
|
||||
|
||||
bool isGccCompiler(const QString &compilerName)
|
||||
{
|
||||
return compilerName.contains("gcc") || compilerName.contains("g++");
|
||||
}
|
||||
|
||||
Core::Id getCompilerId(QString compilerName)
|
||||
{
|
||||
if (Utils::HostOsInfo::isWindowsHost()) {
|
||||
if (compilerName.endsWith(".exe"))
|
||||
compilerName.chop(4);
|
||||
if (isGccCompiler(compilerName))
|
||||
return ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID;
|
||||
|
||||
// Default is clang-cl
|
||||
return ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID;
|
||||
}
|
||||
if (isGccCompiler(compilerName))
|
||||
return ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID;
|
||||
|
||||
// Default is clang
|
||||
return ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID;
|
||||
}
|
||||
|
||||
ToolChain *toolchainFromCompilerId(const Core::Id &compilerId, const Core::Id &language)
|
||||
{
|
||||
return ToolChainManager::toolChain([&compilerId, &language](const ToolChain *tc) {
|
||||
if (!tc->isValid() || tc->language() != language)
|
||||
return false;
|
||||
return tc->typeId() == compilerId;
|
||||
});
|
||||
}
|
||||
|
||||
QString compilerPath(QString pathFlag)
|
||||
{
|
||||
if (pathFlag.isEmpty())
|
||||
return pathFlag;
|
||||
#ifdef Q_OS_WIN
|
||||
// Handle short DOS style file names (cmake can generate them).
|
||||
const DWORD pathLength = GetLongPathNameW((LPCWSTR)pathFlag.utf16(), 0, 0);
|
||||
wchar_t* buffer = new wchar_t[pathLength];
|
||||
GetLongPathNameW((LPCWSTR)pathFlag.utf16(), buffer, pathLength);
|
||||
pathFlag = QString::fromUtf16((ushort *)buffer, pathLength - 1);
|
||||
delete[] buffer;
|
||||
#endif
|
||||
return QDir::fromNativeSeparators(pathFlag);
|
||||
}
|
||||
|
||||
ToolChain *toolchainFromFlags(const Kit *kit, const QStringList &flags, const Core::Id &language)
|
||||
{
|
||||
if (flags.empty())
|
||||
return ToolChainKitInformation::toolChain(kit, language);
|
||||
|
||||
// Try exact compiler match.
|
||||
const Utils::FileName compiler = Utils::FileName::fromString(compilerPath(flags.front()));
|
||||
ToolChain *toolchain = ToolChainManager::toolChain([&compiler, &language](const ToolChain *tc) {
|
||||
return tc->isValid() && tc->language() == language && tc->compilerCommand() == compiler;
|
||||
});
|
||||
if (toolchain)
|
||||
return toolchain;
|
||||
|
||||
Core::Id compilerId = getCompilerId(compiler.fileName());
|
||||
if ((toolchain = toolchainFromCompilerId(compilerId, language)))
|
||||
return toolchain;
|
||||
|
||||
if (compilerId != ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID &&
|
||||
compilerId != ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID) {
|
||||
compilerId = Utils::HostOsInfo::isWindowsHost()
|
||||
? ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID
|
||||
: ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID;
|
||||
if ((toolchain = toolchainFromCompilerId(compilerId, language)))
|
||||
return toolchain;
|
||||
}
|
||||
|
||||
toolchain = ToolChainKitInformation::toolChain(kit, language);
|
||||
qWarning() << QCoreApplication::translate("CompilationDatabaseProject",
|
||||
"No matching toolchain found, use the default.");
|
||||
return toolchain;
|
||||
}
|
||||
|
||||
Utils::FileName jsonObjectFilename(const QJsonObject &object)
|
||||
{
|
||||
const QString workingDir = object["directory"].toString();
|
||||
Utils::FileName fileName = Utils::FileName::fromString(
|
||||
QDir::fromNativeSeparators(object["file"].toString()));
|
||||
if (fileName.toFileInfo().isRelative()) {
|
||||
fileName = Utils::FileUtils::canonicalPath(
|
||||
Utils::FileName::fromString(workingDir + "/" + fileName.toString()));
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
void addDriverModeFlagIfNeeded(const ToolChain *toolchain, QStringList &flags)
|
||||
{
|
||||
if (toolchain->typeId() == ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID
|
||||
&& !flags.empty() && !flags.front().endsWith("cl")
|
||||
&& !flags.front().endsWith("cl.exe")) {
|
||||
flags.insert(1, "--driver-mode=g++");
|
||||
}
|
||||
}
|
||||
|
||||
CppTools::RawProjectPart makeRawProjectPart(const Utils::FileName &projectFile,
|
||||
Kit *kit,
|
||||
ToolChain *&cToolchain,
|
||||
ToolChain *&cxxToolchain,
|
||||
const QString &workingDir,
|
||||
const Utils::FileName &fileName,
|
||||
QStringList flags)
|
||||
{
|
||||
HeaderPaths headerPaths;
|
||||
Macros macros;
|
||||
CppTools::ProjectFile::Kind fileKind = CppTools::ProjectFile::Unclassified;
|
||||
|
||||
const QStringList originalFlags = flags;
|
||||
filteredFlags(fileName.fileName(),
|
||||
workingDir,
|
||||
flags,
|
||||
headerPaths,
|
||||
macros,
|
||||
fileKind);
|
||||
|
||||
CppTools::RawProjectPart rpp;
|
||||
rpp.setProjectFileLocation(projectFile.toString());
|
||||
rpp.setBuildSystemTarget(workingDir);
|
||||
rpp.setDisplayName(fileName.fileName());
|
||||
rpp.setFiles({fileName.toString()});
|
||||
rpp.setHeaderPaths(headerPaths);
|
||||
rpp.setMacros(macros);
|
||||
|
||||
CppTools::RawProjectPartFlags cxxProjectFlags;
|
||||
cxxProjectFlags.commandLineFlags = flags;
|
||||
rpp.setFlagsForCxx(cxxProjectFlags);
|
||||
if (fileKind == CppTools::ProjectFile::Kind::CHeader
|
||||
|| fileKind == CppTools::ProjectFile::Kind::CSource) {
|
||||
if (!cToolchain) {
|
||||
cToolchain = toolchainFromFlags(kit, originalFlags,
|
||||
ProjectExplorer::Constants::C_LANGUAGE_ID);
|
||||
ToolChainKitInformation::setToolChain(kit, cToolchain);
|
||||
}
|
||||
addDriverModeFlagIfNeeded(cToolchain, flags);
|
||||
rpp.setFlagsForC({cToolchain, flags});
|
||||
} else {
|
||||
if (!cxxToolchain) {
|
||||
cxxToolchain = toolchainFromFlags(kit, originalFlags,
|
||||
ProjectExplorer::Constants::CXX_LANGUAGE_ID);
|
||||
ToolChainKitInformation::setToolChain(kit, cxxToolchain);
|
||||
}
|
||||
addDriverModeFlagIfNeeded(cxxToolchain, flags);
|
||||
rpp.setFlagsForCxx({cxxToolchain, flags});
|
||||
}
|
||||
|
||||
return rpp;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void CompilationDatabaseProject::buildTreeAndProjectParts(const Utils::FileName &projectFile)
|
||||
{
|
||||
QFile file(projectFilePath().toString());
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
emitParsingFinished(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const QJsonArray array = QJsonDocument::fromJson(file.readAll()).array();
|
||||
|
||||
auto root = std::make_unique<DBProjectNode>(projectDirectory());
|
||||
root->addNode(std::make_unique<FileNode>(
|
||||
projectFile,
|
||||
FileType::Project,
|
||||
false));
|
||||
auto headers = std::make_unique<VirtualFolderNode>(
|
||||
Utils::FileName::fromString("Headers"), 0);
|
||||
auto sources = std::make_unique<VirtualFolderNode>(
|
||||
Utils::FileName::fromString("Sources"), 0);
|
||||
|
||||
CppTools::RawProjectParts rpps;
|
||||
ToolChain *cToolchain = nullptr;
|
||||
ToolChain *cxxToolchain = nullptr;
|
||||
for (const QJsonValue &element : array) {
|
||||
const QJsonObject object = element.toObject();
|
||||
|
||||
Utils::FileName fileName = jsonObjectFilename(object);
|
||||
const QStringList flags = jsonObjectFlags(object);
|
||||
const QString filePath = fileName.toString();
|
||||
|
||||
const CppTools::ProjectFile::Kind kind = CppTools::ProjectFile::classify(filePath);
|
||||
FolderNode *parent = nullptr;
|
||||
FileType type = FileType::Unknown;
|
||||
if (CppTools::ProjectFile::isHeader(kind)) {
|
||||
parent = headers.get();
|
||||
type = FileType::Header;
|
||||
} else if (CppTools::ProjectFile::isSource(kind)) {
|
||||
parent = sources.get();
|
||||
type = FileType::Source;
|
||||
} else {
|
||||
parent = root.get();
|
||||
}
|
||||
parent->addNode(std::make_unique<FileNode>(fileName, type, false));
|
||||
|
||||
CppTools::RawProjectPart rpp = makeRawProjectPart(projectFile,
|
||||
m_kit.get(),
|
||||
cToolchain,
|
||||
cxxToolchain,
|
||||
object["directory"].toString(),
|
||||
fileName,
|
||||
flags);
|
||||
int rppIndex = Utils::indexOf(rpps, [&rpp](const CppTools::RawProjectPart ¤tRpp) {
|
||||
return rpp.buildSystemTarget == currentRpp.buildSystemTarget
|
||||
&& rpp.headerPaths == currentRpp.headerPaths
|
||||
&& rpp.projectMacros == currentRpp.projectMacros
|
||||
&& rpp.flagsForCxx.commandLineFlags == currentRpp.flagsForCxx.commandLineFlags;
|
||||
});
|
||||
if (rppIndex == -1)
|
||||
rpps.append(rpp);
|
||||
else
|
||||
rpps[rppIndex].files.append(rpp.files);
|
||||
}
|
||||
|
||||
root->addNode(std::move(headers));
|
||||
root->addNode(std::move(sources));
|
||||
|
||||
setRootProjectNode(std::move(root));
|
||||
|
||||
m_cppCodeModelUpdater->update({this, cToolchain, cxxToolchain, m_kit.get(), rpps});
|
||||
|
||||
emitParsingFinished(true);
|
||||
}
|
||||
|
||||
CompilationDatabaseProject::CompilationDatabaseProject(const Utils::FileName &projectFile)
|
||||
: Project(Constants::COMPILATIONDATABASEMIMETYPE, projectFile)
|
||||
, m_cppCodeModelUpdater(std::make_unique<CppTools::CppProjectUpdater>(this))
|
||||
@@ -185,90 +313,17 @@ CompilationDatabaseProject::CompilationDatabaseProject(const Utils::FileName &pr
|
||||
setId(Constants::COMPILATIONDATABASEPROJECT_ID);
|
||||
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
|
||||
setDisplayName(projectDirectory().fileName());
|
||||
setRequiredKitPredicate([](const Kit *) { return false; });
|
||||
setPreferredKitPredicate([](const Kit *) { return false; });
|
||||
|
||||
connect(this, &Project::activeTargetChanged, [this, projectFile](ProjectExplorer::Target *target) {
|
||||
if (!target)
|
||||
return;
|
||||
m_kit.reset(KitManager::defaultKit()->clone());
|
||||
|
||||
ProjectExplorer::Kit *kit = target->kit();
|
||||
if (!kit)
|
||||
return;
|
||||
emitParsingStarted();
|
||||
|
||||
auto toolchains = ProjectExplorer::ToolChainKitInformation::toolChains(kit);
|
||||
if (toolchains.isEmpty())
|
||||
return;
|
||||
|
||||
emitParsingStarted();
|
||||
|
||||
const QFuture<void> future = ::Utils::runAsync([this, projectFile, kit,
|
||||
tc = toolchains.first()](){
|
||||
QFile file(projectFilePath().toString());
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
emitParsingFinished(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const QJsonArray array = QJsonDocument::fromJson(file.readAll()).array();
|
||||
|
||||
auto root = std::make_unique<DBProjectNode>(projectDirectory());
|
||||
root->addNode(std::make_unique<ProjectExplorer::FileNode>(
|
||||
projectFile,
|
||||
ProjectExplorer::FileType::Project,
|
||||
false));
|
||||
auto headers = std::make_unique<ProjectExplorer::VirtualFolderNode>(
|
||||
Utils::FileName::fromString("Headers"), 0);
|
||||
auto sources = std::make_unique<ProjectExplorer::VirtualFolderNode>(
|
||||
Utils::FileName::fromString("Sources"), 0);
|
||||
CppTools::RawProjectParts rpps;
|
||||
for (const QJsonValue &element : array) {
|
||||
const QJsonObject object = element.toObject();
|
||||
const QString workingDir = object["directory"].toString();
|
||||
Utils::FileName fileName = Utils::FileName::fromString(
|
||||
QDir::fromNativeSeparators(object["file"].toString()));
|
||||
if (!fileName.exists()) {
|
||||
fileName = Utils::FileUtils::canonicalPath(
|
||||
Utils::FileName::fromString(workingDir + "/" + fileName.toString()));
|
||||
}
|
||||
const QString filePath = fileName.toString();
|
||||
const CppTools::ProjectFile::Kind kind = CppTools::ProjectFile::classify(filePath);
|
||||
ProjectExplorer::FolderNode *parent = nullptr;
|
||||
ProjectExplorer::FileType type = ProjectExplorer::FileType::Unknown;
|
||||
if (CppTools::ProjectFile::isHeader(kind)) {
|
||||
parent = headers.get();
|
||||
type = ProjectExplorer::FileType::Header;
|
||||
} else if (CppTools::ProjectFile::isSource(kind)) {
|
||||
parent = sources.get();
|
||||
type = ProjectExplorer::FileType::Source;
|
||||
} else {
|
||||
parent = root.get();
|
||||
}
|
||||
parent->addNode(std::make_unique<ProjectExplorer::FileNode>(
|
||||
fileName, type, false));
|
||||
|
||||
rpps.append(makeRawProjectPart(projectFile, object, workingDir, fileName));
|
||||
}
|
||||
|
||||
root->addNode(std::move(headers));
|
||||
root->addNode(std::move(sources));
|
||||
|
||||
setRootProjectNode(std::move(root));
|
||||
|
||||
CppTools::ToolChainInfo tcInfo;
|
||||
tcInfo.type = ProjectExplorer::Constants::COMPILATION_DATABASE_TOOLCHAIN_TYPEID;
|
||||
tcInfo.isMsvc2015ToolChain
|
||||
= tc->targetAbi().osFlavor() == ProjectExplorer::Abi::WindowsMsvc2015Flavor;
|
||||
tcInfo.wordWidth = tc->targetAbi().wordWidth();
|
||||
tcInfo.targetTriple = tc->originalTargetTriple();
|
||||
tcInfo.sysRootPath = ProjectExplorer::SysRootKitInformation::sysRoot(kit).toString();
|
||||
tcInfo.headerPathsRunner = tc->createBuiltInHeaderPathsRunner();
|
||||
tcInfo.macroInspectionRunner = tc->createMacroInspectionRunner();
|
||||
|
||||
m_cppCodeModelUpdater->update({this, tcInfo, tcInfo, rpps});
|
||||
|
||||
emitParsingFinished(true);
|
||||
});
|
||||
m_parserWatcher.setFuture(future);
|
||||
const QFuture<void> future = ::Utils::runAsync([this, projectFile](){
|
||||
buildTreeAndProjectParts(projectFile);
|
||||
});
|
||||
m_parserWatcher.setFuture(future);
|
||||
}
|
||||
|
||||
CompilationDatabaseProject::~CompilationDatabaseProject()
|
||||
|
@@ -35,6 +35,8 @@ namespace CppTools {
|
||||
class CppProjectUpdater;
|
||||
}
|
||||
|
||||
namespace ProjectExplorer { class Kit; }
|
||||
|
||||
namespace CompilationDatabaseProjectManager {
|
||||
namespace Internal {
|
||||
|
||||
@@ -45,10 +47,15 @@ class CompilationDatabaseProject : public ProjectExplorer::Project
|
||||
public:
|
||||
explicit CompilationDatabaseProject(const Utils::FileName &filename);
|
||||
~CompilationDatabaseProject() override;
|
||||
bool needsConfiguration() const override { return false; }
|
||||
bool needsBuildConfigurations() const override { return false; }
|
||||
|
||||
private:
|
||||
void buildTreeAndProjectParts(const Utils::FileName &projectFile);
|
||||
|
||||
QFutureWatcher<void> m_parserWatcher;
|
||||
std::unique_ptr<CppTools::CppProjectUpdater> m_cppCodeModelUpdater;
|
||||
std::unique_ptr<ProjectExplorer::Kit> m_kit;
|
||||
};
|
||||
|
||||
class CompilationDatabaseEditorFactory : public TextEditor::TextEditorFactory
|
||||
|
@@ -2,9 +2,21 @@ include(../../qtcreatorplugin.pri)
|
||||
|
||||
SOURCES = \
|
||||
compilationdatabaseproject.cpp \
|
||||
compilationdatabaseprojectmanagerplugin.cpp
|
||||
compilationdatabaseprojectmanagerplugin.cpp \
|
||||
compilationdatabaseutils.cpp
|
||||
|
||||
HEADERS = \
|
||||
compilationdatabaseproject.h \
|
||||
compilationdatabaseprojectmanagerplugin.h \
|
||||
compilationdatabaseconstants.h
|
||||
compilationdatabaseconstants.h \
|
||||
compilationdatabaseutils.h
|
||||
|
||||
equals(TEST, 1) {
|
||||
HEADERS += \
|
||||
compilationdatabasetests.h
|
||||
|
||||
SOURCES += \
|
||||
compilationdatabasetests.cpp
|
||||
|
||||
RESOURCES += compilationdatabasetests.qrc
|
||||
}
|
||||
|
@@ -13,7 +13,26 @@ QtcPlugin {
|
||||
"compilationdatabaseconstants.h",
|
||||
"compilationdatabaseproject.cpp",
|
||||
"compilationdatabaseproject.h",
|
||||
"compilationdatabaseutils.cpp",
|
||||
"compilationdatabaseutils.h",
|
||||
"compilationdatabaseprojectmanagerplugin.cpp",
|
||||
"compilationdatabaseprojectmanagerplugin.h",
|
||||
]
|
||||
|
||||
Group {
|
||||
name: "Tests"
|
||||
condition: qtc.testsEnabled
|
||||
files: [
|
||||
"compilationdatabasetests.cpp",
|
||||
"compilationdatabasetests.h",
|
||||
"compilationdatabasetests.qrc",
|
||||
]
|
||||
}
|
||||
|
||||
Group {
|
||||
name: "Test resources"
|
||||
prefix: "database_samples/"
|
||||
fileTags: []
|
||||
files: ["**/*"]
|
||||
}
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "compilationdatabaseconstants.h"
|
||||
#include "compilationdatabaseproject.h"
|
||||
#include "compilationdatabasetests.h"
|
||||
|
||||
#include <coreplugin/fileiconprovider.h>
|
||||
#include <projectexplorer/projectmanager.h>
|
||||
@@ -52,5 +53,14 @@ void CompilationDatabaseProjectManagerPlugin::extensionsInitialized()
|
||||
{
|
||||
}
|
||||
|
||||
QList<QObject *> CompilationDatabaseProjectManagerPlugin::createTestObjects() const
|
||||
{
|
||||
QList<QObject *> tests;
|
||||
#ifdef WITH_TESTS
|
||||
tests << new CompilationDatabaseTests;
|
||||
#endif
|
||||
return tests;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace CompilationDatabaseProjectManager
|
||||
|
@@ -43,6 +43,8 @@ public:
|
||||
bool initialize(const QStringList &arguments, QString *errorMessage) final;
|
||||
void extensionsInitialized() final;
|
||||
private:
|
||||
QList<QObject *> createTestObjects() const final;
|
||||
|
||||
CompilationDatabaseEditorFactory factory;
|
||||
};
|
||||
|
||||
|
@@ -0,0 +1,105 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "compilationdatabasetests.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <cpptools/cpptoolstestcase.h>
|
||||
#include <cpptools/projectinfo.h>
|
||||
#include <projectexplorer/kitinformation.h>
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/toolchain.h>
|
||||
#include <projectexplorer/toolchainmanager.h>
|
||||
|
||||
#include <QtTest>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
namespace CompilationDatabaseProjectManager {
|
||||
|
||||
CompilationDatabaseTests::CompilationDatabaseTests(QObject *parent)
|
||||
: QObject(parent)
|
||||
{}
|
||||
|
||||
CompilationDatabaseTests::~CompilationDatabaseTests() = default;
|
||||
|
||||
void CompilationDatabaseTests::initTestCase()
|
||||
{
|
||||
const QList<Kit *> allKits = KitManager::kits();
|
||||
if (allKits.empty())
|
||||
QSKIP("This test requires at least one kit to be present.");
|
||||
|
||||
ToolChain *toolchain = ToolChainManager::toolChain([](const ToolChain *tc) {
|
||||
return tc->isValid() && tc->language() == Constants::CXX_LANGUAGE_ID;
|
||||
});
|
||||
if (!toolchain)
|
||||
QSKIP("This test requires that there is at least one C++ toolchain present.");
|
||||
|
||||
m_tmpDir = std::make_unique<CppTools::Tests::TemporaryCopiedDir>(":/database_samples");
|
||||
QVERIFY(m_tmpDir->isValid());
|
||||
}
|
||||
|
||||
void CompilationDatabaseTests::cleanupTestCase()
|
||||
{
|
||||
m_tmpDir.reset();
|
||||
}
|
||||
|
||||
void CompilationDatabaseTests::testProject()
|
||||
{
|
||||
QFETCH(QString, projectFilePath);
|
||||
|
||||
CppTools::Tests::ProjectOpenerAndCloser projectManager;
|
||||
const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true);
|
||||
QVERIFY(projectInfo.isValid());
|
||||
|
||||
projectInfo.projectParts();
|
||||
QVector<CppTools::ProjectPart::Ptr> projectParts = projectInfo.projectParts();
|
||||
QVERIFY(!projectParts.isEmpty());
|
||||
|
||||
CppTools::ProjectPart &projectPart = *projectParts.first();
|
||||
QVERIFY(!projectPart.headerPaths.isEmpty());
|
||||
QVERIFY(!projectPart.projectMacros.isEmpty());
|
||||
QVERIFY(!projectPart.toolChainMacros.isEmpty());
|
||||
QVERIFY(!projectPart.files.isEmpty());
|
||||
}
|
||||
|
||||
void CompilationDatabaseTests::testProject_data()
|
||||
{
|
||||
QTest::addColumn<QString>("projectFilePath");
|
||||
|
||||
addTestRow("qtc/compile_commands.json");
|
||||
addTestRow("llvm/compile_commands.json");
|
||||
}
|
||||
|
||||
void CompilationDatabaseTests::addTestRow(const QByteArray &relativeFilePath)
|
||||
{
|
||||
const QString absoluteFilePath = m_tmpDir->absolutePath(relativeFilePath);
|
||||
const QString fileName = QFileInfo(absoluteFilePath).fileName();
|
||||
|
||||
QTest::newRow(fileName.toUtf8().constData()) << absoluteFilePath;
|
||||
}
|
||||
|
||||
} // namespace CompilationDatabaseProjectManager
|
@@ -0,0 +1,54 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <memory>
|
||||
|
||||
namespace CppTools { namespace Tests { class TemporaryCopiedDir; } }
|
||||
|
||||
namespace CompilationDatabaseProjectManager {
|
||||
|
||||
class CompilationDatabaseTests : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CompilationDatabaseTests(QObject *parent = nullptr);
|
||||
~CompilationDatabaseTests();
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void testProject();
|
||||
void testProject_data();
|
||||
|
||||
private:
|
||||
void addTestRow(const QByteArray &relativeFilePath);
|
||||
|
||||
std::unique_ptr<CppTools::Tests::TemporaryCopiedDir> m_tmpDir;
|
||||
};
|
||||
|
||||
} // namespace CompilationDatabaseProjectManager
|
@@ -0,0 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>database_samples/llvm/compile_commands.json</file>
|
||||
<file>database_samples/qtc/compile_commands.json</file>
|
||||
</qresource>
|
||||
</RCC>
|
@@ -0,0 +1,7 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/compilationdatabaseutils.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/compilationdatabaseutils.h
|
@@ -0,0 +1,216 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "compilationdatabaseutils.h"
|
||||
|
||||
#include <projectexplorer/headerpath.h>
|
||||
#include <projectexplorer/projectmacro.h>
|
||||
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/optional.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QRegularExpression>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
namespace CompilationDatabaseProjectManager {
|
||||
|
||||
static QString updatedPathFlag(const QString &pathStr, const QString &workingDir)
|
||||
{
|
||||
QString result = pathStr;
|
||||
if (!QDir(pathStr).exists()
|
||||
&& QDir(workingDir + "/" + pathStr).exists()) {
|
||||
result = workingDir + "/" + pathStr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CppTools::ProjectFile::Kind fileKindFromString(const QString &flag)
|
||||
{
|
||||
using namespace CppTools;
|
||||
if (flag == "c++-header")
|
||||
return ProjectFile::CXXHeader;
|
||||
if (flag == "c-header")
|
||||
return ProjectFile::CHeader;
|
||||
if (flag == "c++" || flag == "/TP" || flag.startsWith("/Tp"))
|
||||
return ProjectFile::CXXSource;
|
||||
if (flag == "c" || flag == "/TC" || flag.startsWith("/Tc"))
|
||||
return ProjectFile::CSource;
|
||||
|
||||
if (flag == "objective-c++")
|
||||
return ProjectFile::ObjCXXSource;
|
||||
if (flag == "objective-c++-header")
|
||||
return ProjectFile::ObjCXXHeader;
|
||||
if (flag == "objective-c")
|
||||
return ProjectFile::ObjCSource;
|
||||
if (flag == "objective-c-header")
|
||||
return ProjectFile::ObjCHeader;
|
||||
|
||||
if (flag == "cl")
|
||||
return ProjectFile::OpenCLSource;
|
||||
if (flag == "cuda")
|
||||
return ProjectFile::CudaSource;
|
||||
|
||||
return ProjectFile::Unclassified;
|
||||
}
|
||||
|
||||
void filteredFlags(const QString &fileName,
|
||||
const QString &workingDir,
|
||||
QStringList &flags,
|
||||
HeaderPaths &headerPaths,
|
||||
Macros ¯os,
|
||||
CppTools::ProjectFile::Kind &fileKind)
|
||||
{
|
||||
if (flags.isEmpty())
|
||||
return;
|
||||
|
||||
// Skip compiler call if present.
|
||||
bool skipNext = Utils::HostOsInfo::isWindowsHost()
|
||||
? (!flags.first().startsWith('/') && !flags.first().startsWith('-'))
|
||||
: (!flags.first().startsWith('-'));
|
||||
Utils::optional<HeaderPathType> includePathType;
|
||||
Utils::optional<MacroType> macroType;
|
||||
bool fileKindIsNext = false;
|
||||
|
||||
QStringList filtered;
|
||||
for (const QString &flag : flags) {
|
||||
if (skipNext) {
|
||||
skipNext = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (includePathType) {
|
||||
const QString pathStr = updatedPathFlag(flag, workingDir);
|
||||
headerPaths.append({pathStr, includePathType.value()});
|
||||
includePathType.reset();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (macroType) {
|
||||
Macro macro = Macro::fromKeyValue(flag);
|
||||
macro.type = macroType.value();
|
||||
macros.append(macro);
|
||||
macroType.reset();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileKindIsNext || flag == "/TC" || flag == "/TP"
|
||||
|| flag.startsWith("/Tc") || flag.startsWith("/Tp")) {
|
||||
fileKindIsNext = false;
|
||||
fileKind = fileKindFromString(flag);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flag == "-x") {
|
||||
fileKindIsNext = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flag == "-c" || flag == "-pedantic"
|
||||
|| flag.startsWith("-O") || flag.startsWith("-W") || flag.startsWith("-w")
|
||||
|| QString::compare(flag, "-fpic", Qt::CaseInsensitive) == 0
|
||||
|| QString::compare(flag, "-fpie", Qt::CaseInsensitive) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flag.endsWith(fileName))
|
||||
continue;
|
||||
|
||||
if ((flag.startsWith("-I") || flag.startsWith("-isystem") || flag.startsWith("/I"))
|
||||
&& flag != "-I" && flag != "-isystem" && flag != "/I") {
|
||||
bool userInclude = flag.startsWith("-I");
|
||||
const QString pathStr = updatedPathFlag(flag.mid(userInclude ? 2 : 8),
|
||||
workingDir);
|
||||
headerPaths.append({pathStr, userInclude
|
||||
? HeaderPathType::User
|
||||
: HeaderPathType::System});
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((flag.startsWith("-D") || flag.startsWith("-U") || flag.startsWith("/D") || flag.startsWith("/U"))
|
||||
&& flag != "-D" && flag != "-U" && flag != "/D" && flag != "/U") {
|
||||
Macro macro = Macro::fromKeyValue(flag.mid(2));
|
||||
macro.type = (flag.startsWith("-D") || flag.startsWith("/D")) ? MacroType::Define : MacroType::Undefine;
|
||||
macros.append(macro);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flag == "-I" || flag == "-isystem" || flag == "/I") {
|
||||
includePathType = (flag != "-isystem") ? HeaderPathType::User : HeaderPathType::System;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flag == "-D" || flag == "-U" || flag == "/D" || flag == "/U") {
|
||||
macroType = (flag == "-D" || flag == "/D") ? MacroType::Define : MacroType::Undefine;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((flag.startsWith("-std=") || flag.startsWith("/std:"))
|
||||
&& fileKind == CppTools::ProjectFile::Unclassified) {
|
||||
const bool cpp = (flag.contains("c++") || flag.contains("gnu++"));
|
||||
if (CppTools::ProjectFile::isHeader(CppTools::ProjectFile::classify(fileName)))
|
||||
fileKind = cpp ? CppTools::ProjectFile::CXXHeader : CppTools::ProjectFile::CHeader;
|
||||
else
|
||||
fileKind = cpp ? CppTools::ProjectFile::CXXSource : CppTools::ProjectFile::CXXHeader;
|
||||
}
|
||||
|
||||
// Skip all remaining Windows flags except feature flags.
|
||||
if (flag.startsWith("/") && !flag.startsWith("/Z"))
|
||||
continue;
|
||||
|
||||
filtered.push_back(flag);
|
||||
}
|
||||
|
||||
if (fileKind == CppTools::ProjectFile::Unclassified)
|
||||
fileKind = CppTools::ProjectFile::classify(fileName);
|
||||
|
||||
flags = filtered;
|
||||
}
|
||||
|
||||
QStringList splitCommandLine(QString commandLine)
|
||||
{
|
||||
QStringList result;
|
||||
bool insideQuotes = false;
|
||||
|
||||
// Remove escaped quotes.
|
||||
commandLine.replace("\\\"", "'");
|
||||
for (const QString &part : commandLine.split(QRegularExpression("\""))) {
|
||||
if (insideQuotes) {
|
||||
const QString quotedPart = "\"" + part + "\"";
|
||||
if (result.last().endsWith("="))
|
||||
result.last().append(quotedPart);
|
||||
else
|
||||
result.append(quotedPart);
|
||||
} else { // If 's' is outside quotes ...
|
||||
result.append(part.split(QRegularExpression("\\s+"), QString::SkipEmptyParts));
|
||||
}
|
||||
insideQuotes = !insideQuotes;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace CompilationDatabaseProjectManager
|
@@ -0,0 +1,50 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "compilationdatabaseconstants.h"
|
||||
|
||||
#include <cpptools/cppprojectfile.h>
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class HeaderPath;
|
||||
class Macro;
|
||||
}
|
||||
|
||||
namespace CompilationDatabaseProjectManager {
|
||||
|
||||
void filteredFlags(const QString &fileName,
|
||||
const QString &workingDir,
|
||||
QStringList &flags,
|
||||
QVector<ProjectExplorer::HeaderPath> &headerPaths,
|
||||
QVector<ProjectExplorer::Macro> ¯os,
|
||||
CppTools::ProjectFile::Kind &fileKind);
|
||||
|
||||
QStringList splitCommandLine(QString commandLine);
|
||||
|
||||
} // namespace CompilationDatabaseProjectManager
|
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"directory": "C:/build-qt_llvm-msvc2017_64bit-Debug",
|
||||
"command": "C:\\PROGRA~2\\MICROS~2\\2017\\COMMUN~1\\VC\\Tools\\MSVC\\1415~1.267\\bin\\HostX64\\x64\\cl.exe /nologo /TP -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GNU_SOURCE -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Dclang=clang_qtcreator -Dllvm=llvm_qtcreator -Itools\\clang\\lib\\Sema -IC:\\qt_llvm\\tools\\clang\\lib\\Sema -IC:\\qt_llvm\\tools\\clang\\include -Itools\\clang\\include -Iinclude -IC:\\qt_llvm\\include /DWIN32 /D_WINDOWS /Zc:inline /Zc:strictStrings /Oi /Zc:rvalueCast /W4 -wd4141 -wd4146 -wd4180 -wd4244 -wd4258 -wd4267 -wd4291 -wd4345 -wd4351 -wd4355 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4800 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4324 -w14062 -we4238 /MDd /Zi /Ob0 /Od /RTC1 /EHs-c- /GR /Fotools\\clang\\lib\\Sema\\CMakeFiles\\clangSema.dir\\SemaCodeComplete.cpp.obj /FdTARGET_COMPILE_PDB /FS -c C:\\qt_llvm\\tools\\clang\\lib\\Sema\\SemaCodeComplete.cpp",
|
||||
"file": "C:\\qt_llvm\\tools\\clang\\lib\\Sema\\SemaCodeComplete.cpp"
|
||||
}
|
||||
]
|
@@ -0,0 +1,62 @@
|
||||
[
|
||||
{
|
||||
"arguments": [
|
||||
"clang++",
|
||||
"-c",
|
||||
"-m32",
|
||||
"-target",
|
||||
"i686-w64-mingw32",
|
||||
"-std=gnu++14",
|
||||
"-fcxx-exceptions",
|
||||
"-fexceptions",
|
||||
"-DUNICODE",
|
||||
"-D_UNICODE",
|
||||
"-DCPPTOOLS_LIBRARY",
|
||||
"-DWITH_TESTS",
|
||||
"-DRELATIVE_PLUGIN_PATH=\"../lib/qtcreator/plugins\"",
|
||||
"-DRELATIVE_LIBEXEC_PATH=\".\"",
|
||||
"-DRELATIVE_DATA_PATH=\"../share/qtcreator\"",
|
||||
"-DRELATIVE_DOC_PATH=\"../share/doc/qtcreator\"",
|
||||
"-DIDE_LIBRARY_BASENAME=\"lib\"",
|
||||
"-DQT_CREATOR",
|
||||
"-DQT_NO_CAST_TO_ASCII",
|
||||
"-DQT_RESTRICTED_CAST_FROM_ASCII",
|
||||
"-DQT_DISABLE_DEPRECATED_BEFORE=0x050600",
|
||||
"-DQT_USE_FAST_OPERATOR_PLUS",
|
||||
"-DQT_USE_FAST_CONCATENATION",
|
||||
"-DSRCDIR=\"C:/qt-creator/src/plugins/cpptools\"",
|
||||
"-DQT_QML_DEBUG",
|
||||
"-DQT_PLUGIN",
|
||||
"-DQT_WIDGETS_LIB",
|
||||
"-DQT_GUI_LIB",
|
||||
"-DQT_TESTLIB_LIB",
|
||||
"-DQT_CONCURRENT_LIB",
|
||||
"-DQT_NETWORK_LIB",
|
||||
"-DQT_CORE_LIB",
|
||||
"-fPIC",
|
||||
"-I",
|
||||
"C:\\Qt\\5.9.2\\mingw53_32\\include",
|
||||
"-I",
|
||||
"C:\\Qt\\5.9.2\\mingw53_32\\include\\QtWidgets",
|
||||
"-I",
|
||||
"C:\\Qt\\5.9.2\\mingw53_32\\include\\QtGui",
|
||||
"-I",
|
||||
"C:\\Qt\\5.9.2\\mingw53_32\\include\\QtANGLE",
|
||||
"-I",
|
||||
"C:\\Qt\\5.9.2\\mingw53_32\\include\\QtTest",
|
||||
"-I",
|
||||
"C:\\Qt\\5.9.2\\mingw53_32\\include\\QtConcurrent",
|
||||
"-I",
|
||||
"C:\\Qt\\5.9.2\\mingw53_32\\include\\QtNetwork",
|
||||
"-I",
|
||||
"C:\\Qt\\5.9.2\\mingw53_32\\include\\QtCore",
|
||||
"-I",
|
||||
"C:\\Qt\\5.9.2\\mingw53_32\\mkspecs\\win32-g++",
|
||||
"-x",
|
||||
"c++",
|
||||
"C:\\qt-creator\\src\\plugins\\cpptools\\compileroptionsbuilder.cpp"
|
||||
],
|
||||
"directory": "C:/build-qtcreator-MinGW_32bit-Debug",
|
||||
"file": "C:/qt-creator/src/plugins/cpptools/compileroptionsbuilder.cpp"
|
||||
}
|
||||
]
|
@@ -76,13 +76,6 @@ QStringList CompilerOptionsBuilder::build(CppTools::ProjectFile::Kind fileKind,
|
||||
addTargetTriple();
|
||||
addExtraCodeModelFlags();
|
||||
|
||||
if (m_projectPart.toolchainType
|
||||
== ProjectExplorer::Constants::COMPILATION_DATABASE_TOOLCHAIN_TYPEID) {
|
||||
addHeaderPathOptions();
|
||||
insertWrappedQtHeaders();
|
||||
return options();
|
||||
}
|
||||
|
||||
updateLanguageOption(fileKind);
|
||||
addOptionsForLanguage(/*checkForBorlandExtensions*/ true);
|
||||
enableExceptions();
|
||||
|
@@ -165,9 +165,6 @@ ProjectPart::Ptr ProjectInfoGenerator::createProjectPart(
|
||||
part->warningFlags = flags.warningFlags;
|
||||
part->languageExtensions = flags.languageExtensions;
|
||||
|
||||
if (part->toolchainType == ProjectExplorer::Constants::COMPILATION_DATABASE_TOOLCHAIN_TYPEID)
|
||||
part->extraCodeModelFlags = flags.commandLineFlags;
|
||||
|
||||
// Toolchain macros and language version
|
||||
if (tcInfo.macroInspectionRunner) {
|
||||
auto macroInspectionReport = tcInfo.macroInspectionRunner(flags.commandLineFlags);
|
||||
|
@@ -163,7 +163,6 @@ const char MINGW_TOOLCHAIN_TYPEID[] = "ProjectExplorer.ToolChain.Mingw";
|
||||
const char MSVC_TOOLCHAIN_TYPEID[] = "ProjectExplorer.ToolChain.Msvc";
|
||||
const char CLANG_CL_TOOLCHAIN_TYPEID[] = "ProjectExplorer.ToolChain.ClangCl";
|
||||
const char CUSTOM_TOOLCHAIN_TYPEID[] = "ProjectExplorer.ToolChain.Custom";
|
||||
const char COMPILATION_DATABASE_TOOLCHAIN_TYPEID[] = "ProjectExplorer.ToolChain.Empty";
|
||||
|
||||
// Default directory to run custom (build) commands in.
|
||||
const char DEFAULT_WORKING_DIR[] = "%{buildDir}";
|
||||
|
169
tests/unit/unittest/compilationdatabaseutils-test.cpp
Normal file
169
tests/unit/unittest/compilationdatabaseutils-test.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 <compilationdatabaseprojectmanager/compilationdatabaseutils.h>
|
||||
#include <projectexplorer/headerpath.h>
|
||||
#include <projectexplorer/projectmacro.h>
|
||||
#include <utils/fileutils.h>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace CompilationDatabaseProjectManager;
|
||||
|
||||
namespace {
|
||||
|
||||
class CompilationDatabaseUtils : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
HeaderPaths headerPaths;
|
||||
Macros macros;
|
||||
CppTools::ProjectFile::Kind fileKind = CppTools::ProjectFile::Unclassified;
|
||||
QStringList flags;
|
||||
QString fileName;
|
||||
QString workingDir;
|
||||
};
|
||||
|
||||
TEST_F(CompilationDatabaseUtils, FilterEmptyFlags)
|
||||
{
|
||||
filteredFlags(fileName, workingDir, flags, headerPaths, macros, fileKind);
|
||||
|
||||
ASSERT_THAT(flags.isEmpty(), true);
|
||||
}
|
||||
|
||||
TEST_F(CompilationDatabaseUtils, FilterArguments)
|
||||
{
|
||||
fileName = "compileroptionsbuilder.cpp";
|
||||
workingDir = "C:/build-qtcreator-MinGW_32bit-Debug";
|
||||
flags = QStringList {
|
||||
"clang++",
|
||||
"-c",
|
||||
"-m32",
|
||||
"-target",
|
||||
"i686-w64-mingw32",
|
||||
"-std=gnu++14",
|
||||
"-fcxx-exceptions",
|
||||
"-fexceptions",
|
||||
"-DUNICODE",
|
||||
"-DRELATIVE_PLUGIN_PATH=\"../lib/qtcreator/plugins\"",
|
||||
"-DQT_CREATOR",
|
||||
"-fPIC",
|
||||
"-I",
|
||||
"C:\\Qt\\5.9.2\\mingw53_32\\include",
|
||||
"-I",
|
||||
"C:\\Qt\\5.9.2\\mingw53_32\\include\\QtWidgets",
|
||||
"-x",
|
||||
"c++",
|
||||
"C:\\qt-creator\\src\\plugins\\cpptools\\compileroptionsbuilder.cpp"
|
||||
};
|
||||
|
||||
filteredFlags(fileName, workingDir, flags, headerPaths, macros, fileKind);
|
||||
|
||||
ASSERT_THAT(flags, Eq(QStringList{"-m32",
|
||||
"-target",
|
||||
"i686-w64-mingw32",
|
||||
"-std=gnu++14",
|
||||
"-fcxx-exceptions",
|
||||
"-fexceptions"}));
|
||||
ASSERT_THAT(headerPaths, Eq(HeaderPaths{
|
||||
{"C:\\Qt\\5.9.2\\mingw53_32\\include", HeaderPathType::User},
|
||||
{"C:\\Qt\\5.9.2\\mingw53_32\\include\\QtWidgets", HeaderPathType::User}
|
||||
}));
|
||||
ASSERT_THAT(macros, Eq(Macros{
|
||||
{"UNICODE", "1"},
|
||||
{"RELATIVE_PLUGIN_PATH", "\"../lib/qtcreator/plugins\""},
|
||||
{"QT_CREATOR", "1"}
|
||||
}));
|
||||
ASSERT_THAT(fileKind, CppTools::ProjectFile::Kind::CXXSource);
|
||||
}
|
||||
|
||||
static QString kCmakeCommand = "C:\\PROGRA~2\\MICROS~2\\2017\\COMMUN~1\\VC\\Tools\\MSVC\\1415~1.267\\bin\\HostX64\\x64\\cl.exe "
|
||||
"/nologo "
|
||||
"/TP "
|
||||
"-DUNICODE "
|
||||
"-D_HAS_EXCEPTIONS=0 "
|
||||
"-Itools\\clang\\lib\\Sema "
|
||||
"/DWIN32 "
|
||||
"/D_WINDOWS "
|
||||
"/Zc:inline "
|
||||
"/Zc:strictStrings "
|
||||
"/Oi "
|
||||
"/Zc:rvalueCast "
|
||||
"/W4 "
|
||||
"-wd4141 "
|
||||
"-wd4146 "
|
||||
"/MDd "
|
||||
"/Zi "
|
||||
"/Ob0 "
|
||||
"/Od "
|
||||
"/RTC1 "
|
||||
"/EHs-c- "
|
||||
"/GR "
|
||||
"/Fotools\\clang\\lib\\Sema\\CMakeFiles\\clangSema.dir\\SemaCodeComplete.cpp.obj "
|
||||
"/FdTARGET_COMPILE_PDB "
|
||||
"/FS "
|
||||
"-c "
|
||||
"C:\\qt_llvm\\tools\\clang\\lib\\Sema\\SemaCodeComplete.cpp";
|
||||
|
||||
TEST_F(CompilationDatabaseUtils, SplitFlags)
|
||||
{
|
||||
flags = splitCommandLine(kCmakeCommand);
|
||||
|
||||
ASSERT_THAT(flags.size(), 27);
|
||||
}
|
||||
|
||||
TEST_F(CompilationDatabaseUtils, SplitFlagsWithEscapedQuotes)
|
||||
{
|
||||
flags = splitCommandLine("-DRC_FILE_VERSION=\\\"7.0.0\\\" "
|
||||
"-DRELATIVE_PLUGIN_PATH=\"../lib/qtcreator/plugins\"");
|
||||
|
||||
ASSERT_THAT(flags.size(), 2);
|
||||
}
|
||||
|
||||
TEST_F(CompilationDatabaseUtils, FilterCommand)
|
||||
{
|
||||
fileName = "SemaCodeComplete.cpp";
|
||||
workingDir = "C:/build-qt_llvm-msvc2017_64bit-Debug";
|
||||
flags = splitCommandLine(kCmakeCommand);
|
||||
|
||||
filteredFlags(fileName, workingDir, flags, headerPaths, macros, fileKind);
|
||||
|
||||
ASSERT_THAT(flags, Eq(QStringList{"/Zc:inline",
|
||||
"/Zc:strictStrings",
|
||||
"/Zc:rvalueCast",
|
||||
"/Zi"}));
|
||||
ASSERT_THAT(headerPaths, Eq(HeaderPaths{
|
||||
{"tools\\clang\\lib\\Sema", HeaderPathType::User}
|
||||
}));
|
||||
ASSERT_THAT(macros, Eq(Macros{
|
||||
{"UNICODE", "1"},
|
||||
{"_HAS_EXCEPTIONS", "0"},
|
||||
{"WIN32", "1"},
|
||||
{"_WINDOWS", "1"}
|
||||
}));
|
||||
ASSERT_THAT(fileKind, CppTools::ProjectFile::Kind::CXXSource);
|
||||
}
|
||||
|
||||
}
|
@@ -13,6 +13,7 @@ include($$PWD/../../../src/tools/clangpchmanagerbackend/source/clangpchmanagerba
|
||||
include($$PWD/../../../src/plugins/clangrefactoring/clangrefactoring-source.pri)
|
||||
include($$PWD/../../../src/plugins/clangpchmanager/clangpchmanager-source.pri)
|
||||
include($$PWD/../../../src/plugins/cpptools/cpptoolsunittestfiles.pri)
|
||||
include($$PWD/../../../src/plugins/compilationdatabaseprojectmanager/compilationdatabaseunittestfiles.pri)
|
||||
include(cplusplus.pri)
|
||||
!isEmpty(LLVM_VERSION) {
|
||||
include($$PWD/../../../src/shared/clang/clang_defines.pri)
|
||||
|
@@ -104,7 +104,8 @@ SOURCES += \
|
||||
taskscheduler-test.cpp \
|
||||
compileroptionsbuilder-test.cpp \
|
||||
usedmacroandsourcestorage-test.cpp \
|
||||
pchtaskgenerator-test.cpp
|
||||
pchtaskgenerator-test.cpp \
|
||||
compilationdatabaseutils-test.cpp
|
||||
|
||||
!isEmpty(LIBCLANG_LIBS) {
|
||||
SOURCES += \
|
||||
|
Reference in New Issue
Block a user