Clang: Add BuildDependencyCollector

IncludeCollector is renamed to BuildDependencyCollector. It is now
returning a BuildDependency instead of individual getter. The test coverage
is improved too.

Task-number: QTCREATORBUG-21379
Change-Id: Ifc2d1c40c85772cf498c21968de526f4408b6023
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
Marco Bubke
2018-11-12 19:27:51 +01:00
parent e11ff791f0
commit 64a3a130ac
56 changed files with 1135 additions and 813 deletions

View File

@@ -32,6 +32,7 @@
#include <iterator>
#include <ostream>
#include <sstream>
namespace Utils {
@@ -232,7 +233,19 @@ ostream &operator<<(ostream &out, const vector<T> &vector)
{
out << "[";
copy(vector.cbegin(), vector.cend(), ostream_iterator<T>(out, ", "));
for (auto current = vector.begin(); current != vector.end(); ++current) {
std::ostringstream entryStream;
entryStream << *current;
std::string entryString = entryStream.str();
if (entryString.size() > 4)
out << "\n\t";
out << entryString;
if (std::next(current) != vector.end())
out << ", ";
}
out << "]";

View File

@@ -27,7 +27,7 @@
#include "builddependenciesstorageinterface.h"
#include "modifiedtimecheckerinterface.h"
#include "builddependenciesgeneratorinterface.h"
#include "builddependencygeneratorinterface.h"
#include <algorithm>

View File

@@ -31,14 +31,14 @@ namespace ClangBackEnd {
class BuildDependenciesStorageInterface;
class ModifiedTimeCheckerInterface;
class BuildDependenciesGeneratorInterface;
class BuildDependencyGeneratorInterface;
class BuildDependenciesProvider : public BuildDependenciesProviderInterface
{
public:
BuildDependenciesProvider(BuildDependenciesStorageInterface &buildDependenciesStorage,
ModifiedTimeCheckerInterface &modifiedTimeChecker,
BuildDependenciesGeneratorInterface &buildDependenciesGenerator)
BuildDependencyGeneratorInterface &buildDependenciesGenerator)
: m_buildDependenciesStorage(buildDependenciesStorage),
m_modifiedTimeChecker(modifiedTimeChecker),
m_buildDependenciesGenerator(buildDependenciesGenerator)
@@ -56,7 +56,7 @@ private:
private:
BuildDependenciesStorageInterface &m_buildDependenciesStorage;
ModifiedTimeCheckerInterface &m_modifiedTimeChecker;
BuildDependenciesGeneratorInterface &m_buildDependenciesGenerator;
BuildDependencyGeneratorInterface &m_buildDependenciesGenerator;
};
} // namespace ClangBackEnd

View File

@@ -25,6 +25,8 @@
#pragma once
#include "filestatus.h"
#include "sourcedependency.h"
#include "sourceentry.h"
#include "usedmacro.h"
@@ -32,13 +34,24 @@ namespace ClangBackEnd {
class BuildDependency
{
public:
void clear()
{
includes.clear();
usedMacros.clear();
sourceFiles.clear();
fileStatuses.clear();
sourceDependencies.clear();
}
public:
SourceEntries includes;
FilePathIds topIncludeIds;
FilePathIds topsSystemIncludeIds;
UsedMacros usedMacros;
FilePathIds sourceFiles;
SourceDependencies sourceDependencies;
FileStatuses fileStatuses;
};
using BuildDependencies = std::vector<BuildDependency>;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,124 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "builddependencycollector.h"
#include "collectbuilddependencytoolaction.h"
#include <utils/smallstring.h>
#include <algorithm>
namespace ClangBackEnd {
namespace {
FilePathIds operator+(const FilePathIds &first, const FilePathIds &second)
{
FilePathIds result = first;
std::copy(second.begin(), second.end(), std::back_inserter(result));
return result;
}
}
BuildDependency BuildDependencyCollector::create(const V2::ProjectPartContainer &projectPart)
{
addFiles(projectPart.sourcePathIds, projectPart.arguments);
setExcludedFilePaths(
m_filePathCache.filePaths(projectPart.headerPathIds + projectPart.sourcePathIds));
collect();
return std::move(m_buildDependency);
}
void BuildDependencyCollector::collect()
{
clang::tooling::ClangTool tool = m_clangTool.createTool();
auto action = std::make_unique<CollectBuildDependencyToolAction>(m_buildDependency,
m_filePathCache,
m_excludedFilePaths,
m_sourcesManager);
tool.run(action.get());
}
void BuildDependencyCollector::setExcludedFilePaths(ClangBackEnd::FilePaths &&excludedFilePaths)
{
if (Utils::HostOsInfo::isWindowsHost()) {
m_excludedFilePaths.clear();
m_excludedFilePaths.reserve(excludedFilePaths.size());
std::transform(std::make_move_iterator(excludedFilePaths.begin()),
std::make_move_iterator(excludedFilePaths.end()),
std::back_inserter(m_excludedFilePaths),
[](auto &&path) {
path.replace("/", "\\");
return std::move(path);
});
} else {
m_excludedFilePaths = std::move(excludedFilePaths);
}
}
void BuildDependencyCollector::addFiles(const FilePathIds &filePathIds,
const Utils::SmallStringVector &arguments)
{
m_clangTool.addFiles(m_filePathCache.filePaths(filePathIds), arguments);
m_buildDependency.sourceFiles.insert(m_buildDependency.sourceFiles.end(),
filePathIds.begin(),
filePathIds.end());
}
void BuildDependencyCollector::addFile(FilePathId filePathId,
const Utils::SmallStringVector &arguments)
{
addFiles({filePathId}, arguments);
}
void BuildDependencyCollector::addFile(FilePath filePath,
const FilePathIds &sourceFileIds,
const Utils::SmallStringVector &arguments)
{
m_clangTool.addFiles({filePath}, arguments);
m_buildDependency.sourceFiles.insert(m_buildDependency.sourceFiles.end(),
sourceFileIds.begin(),
sourceFileIds.end());
}
void BuildDependencyCollector::addUnsavedFiles(const V2::FileContainers &unsavedFiles)
{
m_clangTool.addUnsavedFiles(unsavedFiles);
}
void BuildDependencyCollector::clear()
{
m_clangTool = ClangTool();
m_buildDependency.clear();
}
} // namespace ClangBackEnd

View File

@@ -25,27 +25,28 @@
#pragma once
#include "builddependencygeneratorinterface.h"
#include <clangtool.h>
#include <filestatus.h>
#include <sourcedependency.h>
#include <sourcesmanager.h>
#include <usedmacro.h>
#include <filepathcachingfwd.h>
namespace ClangBackEnd {
class IncludeCollector : public ClangTool
class BuildDependencyCollector : public BuildDependencyGeneratorInterface
{
public:
IncludeCollector(const FilePathCachingInterface &filePathCache)
BuildDependencyCollector(const FilePathCachingInterface &filePathCache)
: m_filePathCache(filePathCache)
{
}
BuildDependency create(const V2::ProjectPartContainer &projectPart) override;
void collect();
void setExcludedIncludes(Utils::PathStringVector &&excludedIncludes);
void setExcludedFilePaths(ClangBackEnd::FilePaths &&excludedIncludes);
void addFiles(const FilePathIds &filePathIds,
const Utils::SmallStringVector &arguments);
void addFile(FilePathId filePathId,
@@ -53,62 +54,43 @@ public:
void addFile(FilePath filePath,
const FilePathIds &sourceFileIds,
const Utils::SmallStringVector &arguments);
void addUnsavedFiles(const V2::FileContainers &unsavedFiles);
void clear();
const FileStatuses &fileStatuses() const
{
return m_fileStatuses;
return m_buildDependency.fileStatuses;
}
const FilePathIds &sourceFiles() const
{
return m_sourceFiles;
return m_buildDependency.sourceFiles;
}
const UsedMacros &usedMacros() const
{
return m_usedMacros;
return m_buildDependency.usedMacros;
}
const SourceDependencies &sourceDependencies() const
{
return m_sourceDependencies;
return m_buildDependency.sourceDependencies;
}
FilePathIds takeIncludeIds()
const SourceEntries &includeIds()
{
std::sort(m_includeIds.begin(), m_includeIds.end());
std::sort(m_buildDependency.includes.begin(), m_buildDependency.includes.end());
return std::move(m_includeIds);
}
FilePathIds takeTopIncludeIds()
{
std::sort(m_topIncludeIds.begin(), m_topIncludeIds.end());
return std::move(m_topIncludeIds);
}
FilePathIds takeTopsSystemIncludeIds()
{
std::sort(m_topsSystemIncludeIds.begin(), m_topsSystemIncludeIds.end());
return std::move(m_topsSystemIncludeIds);
return std::move(m_buildDependency.includes);
}
private:
ClangTool m_clangTool;
Utils::PathStringVector m_excludedIncludes;
FilePathIds m_includeIds;
FilePathIds m_topIncludeIds;
FilePathIds m_topsSystemIncludeIds;
BuildDependency m_buildDependency;
ClangBackEnd::FilePaths m_excludedFilePaths;
Utils::SmallStringVector m_directories;
SourcesManager m_sourcesManager;
UsedMacros m_usedMacros;
FilePathIds m_sourceFiles;
SourceDependencies m_sourceDependencies;
FileStatuses m_fileStatuses;
const FilePathCachingInterface &m_filePathCache;
};

View File

@@ -31,13 +31,13 @@
namespace ClangBackEnd {
class BuildDependenciesGeneratorInterface
class BuildDependencyGeneratorInterface
{
public:
virtual BuildDependency create(const V2::ProjectPartContainer &projectPart) = 0;
protected:
~BuildDependenciesGeneratorInterface() = default;
~BuildDependencyGeneratorInterface() = default;
};
} // namespace ClangBackEnd

View File

@@ -5,7 +5,8 @@ SOURCES += \
$$PWD/projectparts.cpp \
$$PWD/projectpartqueue.cpp \
$$PWD/pchtaskgenerator.cpp \
$$PWD/builddependenciesprovider.cpp
$$PWD/builddependenciesprovider.cpp \
$$PWD/builddependencycollector.cpp
HEADERS += \
$$PWD/pchmanagerserver.h \
@@ -32,20 +33,19 @@ HEADERS += \
$$PWD/builddependency.h \
$$PWD/modifiedtimecheckerinterface.h \
$$PWD/sourceentry.h \
$$PWD/builddependenciesgeneratorinterface.h \
$$PWD/builddependenciesstorage.h
$$PWD/builddependenciesstorage.h \
$$PWD/builddependencycollector.h \
$$PWD/builddependencygeneratorinterface.h \
$$PWD/collectbuilddependencytoolaction.h \
$$PWD/collectbuilddependencyaction.h \
$$PWD/collectbuilddependencypreprocessorcallbacks.h
!isEmpty(LIBTOOLING_LIBS) {
SOURCES += \
$$PWD/usedmacrosandsourcescollector.cpp \
$$PWD/includecollector.cpp \
$$PWD/pchcreator.cpp
HEADERS += \
$$PWD/includecollector.h \
$$PWD/collectincludestoolaction.h \
$$PWD/collectincludesaction.h \
$$PWD/collectincludespreprocessorcallbacks.h \
$$PWD/collectusedmacroactionfactory.h \
$$PWD/collectusedmacrosaction.h \
$$PWD/collectusedmacrosandsourcespreprocessorcallbacks.h \

View File

@@ -25,7 +25,7 @@
#pragma once
#include <collectincludespreprocessorcallbacks.h>
#include <collectbuilddependencypreprocessorcallbacks.h>
#include <filepathcachingfwd.h>
#include <filepathid.h>
@@ -36,31 +36,19 @@
namespace ClangBackEnd {
class CollectIncludesAction final : public clang::PreprocessOnlyAction
class CollectBuildDependencyAction final : public clang::PreprocessOnlyAction
{
public:
CollectIncludesAction(FilePathIds &includeIds,
FilePathIds &topIncludeIds,
FilePathIds &topsSystemIncludeIds,
CollectBuildDependencyAction(BuildDependency &buildDependency,
const FilePathCachingInterface &filePathCache,
std::vector<uint> &excludedIncludeUID,
std::vector<uint> &alreadyIncludedFileUIDs,
UsedMacros &usedMacros,
SourcesManager &sourcesManager,
SourceDependencies &sourceDependencies,
FilePathIds &sourceFiles,
FileStatuses &fileStatuses)
: m_includeIds(includeIds),
m_topIncludeIds(topIncludeIds),
m_topsSystemIncludeIds(topsSystemIncludeIds),
SourcesManager &sourcesManager)
: m_buildDependency(buildDependency),
m_filePathCache(filePathCache),
m_excludedIncludeUID(excludedIncludeUID),
m_alreadyIncludedFileUIDs(alreadyIncludedFileUIDs),
m_usedMacros(usedMacros),
m_sourcesManager(sourcesManager),
m_sourceDependencies(sourceDependencies),
m_sourceFiles(sourceFiles),
m_fileStatuses(fileStatuses)
m_sourcesManager(sourcesManager)
{
}
@@ -71,20 +59,14 @@ public:
preprocessor.SetSuppressIncludeNotFoundError(true);
auto macroPreprocessorCallbacks = new CollectIncludesPreprocessorCallbacks(
m_includeIds,
m_topIncludeIds,
m_topsSystemIncludeIds,
auto macroPreprocessorCallbacks = new CollectBuildDependencyPreprocessorCallbacks(
m_buildDependency,
m_filePathCache,
m_excludedIncludeUID,
m_alreadyIncludedFileUIDs,
compilerInstance.getSourceManager(),
m_usedMacros,
m_sourcesManager,
compilerInstance.getPreprocessorPtr(),
m_sourceDependencies,
m_sourceFiles,
m_fileStatuses);
compilerInstance.getPreprocessorPtr());
preprocessor.addPPCallbacks(std::unique_ptr<clang::PPCallbacks>(macroPreprocessorCallbacks));
@@ -100,17 +82,11 @@ public:
}
private:
FilePathIds &m_includeIds;
FilePathIds &m_topIncludeIds;
FilePathIds &m_topsSystemIncludeIds;
BuildDependency &m_buildDependency;
const FilePathCachingInterface &m_filePathCache;
std::vector<uint> &m_excludedIncludeUID;
std::vector<uint> &m_alreadyIncludedFileUIDs;
UsedMacros &m_usedMacros;
SourcesManager &m_sourcesManager;
SourceDependencies &m_sourceDependencies;
FilePathIds &m_sourceFiles;
FileStatuses &m_fileStatuses;
};
} // namespace ClangBackEnd

View File

@@ -25,6 +25,7 @@
#pragma once
#include "builddependency.h"
#include "collectmacrospreprocessorcallbacks.h"
#include "sourcelocationsutils.h"
@@ -33,6 +34,8 @@
#include <utils/smallstringvector.h>
#include <llvm/Support/MemoryBuffer.h>
#include <QFile>
#include <QDir>
#include <QTemporaryDir>
@@ -41,34 +44,26 @@
namespace ClangBackEnd {
class CollectIncludesPreprocessorCallbacks final : public clang::PPCallbacks,
class CollectBuildDependencyPreprocessorCallbacks final : public clang::PPCallbacks,
public CollectUsedMacrosAndSourcesPreprocessorCallbacksBase
{
public:
CollectIncludesPreprocessorCallbacks(FilePathIds &includeIds,
FilePathIds &topIncludeIds,
FilePathIds &topsSystemIncludeIds,
CollectBuildDependencyPreprocessorCallbacks(BuildDependency &buildDependency,
const FilePathCachingInterface &filePathCache,
const std::vector<uint> &excludedIncludeUID,
std::vector<uint> &alreadyIncludedFileUIDs,
const clang::SourceManager &sourceManager,
UsedMacros &usedMacros,
clang::SourceManager &sourceManager,
SourcesManager &sourcesManager,
std::shared_ptr<clang::Preprocessor> preprocessor,
SourceDependencies &sourceDependencies,
FilePathIds &sourceFiles,
FileStatuses &fileStatuses)
: CollectUsedMacrosAndSourcesPreprocessorCallbacksBase(usedMacros,
std::shared_ptr<clang::Preprocessor> preprocessor)
: CollectUsedMacrosAndSourcesPreprocessorCallbacksBase(buildDependency.usedMacros,
filePathCache,
sourceManager,
sourcesManager,
preprocessor,
sourceDependencies,
sourceFiles,
fileStatuses),
m_includeIds(includeIds),
m_topIncludeIds(topIncludeIds),
m_topsSystemIncludeIds(topsSystemIncludeIds),
buildDependency.sourceDependencies,
buildDependency.sourceFiles,
buildDependency.fileStatuses),
m_buildDependency(buildDependency),
m_excludedIncludeUID(excludedIncludeUID),
m_alreadyIncludedFileUIDs(alreadyIncludedFileUIDs)
{}
@@ -90,7 +85,7 @@ public:
}
void InclusionDirective(clang::SourceLocation hashLocation,
const clang::Token &/*includeToken*/,
const clang::Token & /*includeToken*/,
llvm::StringRef /*fileName*/,
bool /*isAngled*/,
clang::CharSourceRange /*fileNameRange*/,
@@ -103,20 +98,30 @@ public:
if (!m_skipInclude && file) {
addSourceDependency(file, hashLocation);
auto fileUID = file->getUID();
auto sourceFileUID = m_sourceManager->getFileEntryForID(m_sourceManager->getFileID(hashLocation))->getUID();
if (isNotInExcludedIncludeUID(fileUID)) {
auto sourceFileUID = m_sourceManager
->getFileEntryForID(m_sourceManager->getFileID(hashLocation))
->getUID();
auto notAlreadyIncluded = isNotAlreadyIncluded(fileUID);
if (notAlreadyIncluded.first) {
m_alreadyIncludedFileUIDs.insert(notAlreadyIncluded.second, fileUID);
FilePath filePath = filePathFromFile(file);
if (!filePath.empty()) {
FilePathId includeId = m_filePathCache.filePathId(filePath);
m_includeIds.emplace_back(includeId);
if (isSystem(fileType) && !isInSystemHeader(hashLocation))
m_topsSystemIncludeIds.emplace_back(includeId);
if (isInExcludedIncludeUID(sourceFileUID))
m_topIncludeIds.emplace_back(includeId);
time_t lastModified = file->getModificationTime();
SourceType sourceType = SourceType::UserInclude;
if (isSystem(fileType)) {
if (isInSystemHeader(hashLocation))
sourceType = SourceType::SystemInclude;
else
sourceType = SourceType::TopSystemInclude;
} else if (isNotInExcludedIncludeUID(fileUID)
&& isInExcludedIncludeUID(sourceFileUID)) {
sourceType = SourceType::TopInclude;
}
addInclude({includeId, sourceType, lastModified});
}
}
}
@@ -124,19 +129,12 @@ public:
m_skipInclude = false;
}
bool FileNotFound(clang::StringRef fileNameRef, clang::SmallVectorImpl<char> &recoveryPath) override
bool FileNotFound(clang::StringRef /*fileNameRef*/,
clang::SmallVectorImpl<char> &recoveryPath) override
{
QTemporaryDir temporaryDirectory;
temporaryDirectory.setAutoRemove(false);
const QByteArray temporaryDirUtf8 = temporaryDirectory.path().toUtf8();
auto dummyPath = llvm::StringRef("/dummyPath");
const QString fileName = QString::fromUtf8(fileNameRef.data(), int(fileNameRef.size()));
QString filePath = temporaryDirectory.path() + '/' + fileName;
ensureDirectory(temporaryDirectory.path(), fileName);
createFakeFile(filePath);
recoveryPath.append(temporaryDirUtf8.cbegin(), temporaryDirUtf8.cend());
recoveryPath.append(std::cbegin(dummyPath), std::cend(dummyPath));
m_skipInclude = true;
@@ -189,15 +187,6 @@ public:
QDir(directory).mkpath(directoryEntries.join('/'));
}
void createFakeFile(const QString &filePath)
{
QFile fakeFile;
fakeFile.setFileName(filePath);
fakeFile.open(QIODevice::ReadWrite);
fakeFile.close();
}
bool isNotInExcludedIncludeUID(uint uid) const
{
return !isInExcludedIncludeUID(uid);
@@ -224,10 +213,21 @@ public:
return FilePath::fromNativeFilePath(absolutePath(file->getName()));
}
void addInclude(SourceEntry sourceEntry)
{
auto &includes = m_buildDependency.includes;
auto found = std::lower_bound(includes.begin(),
includes.end(),
sourceEntry,
[](auto first, auto second) { return first < second; });
if (found == includes.end() || *found != sourceEntry)
includes.emplace(found, sourceEntry);
}
private:
FilePathIds &m_includeIds;
FilePathIds &m_topIncludeIds;
FilePathIds &m_topsSystemIncludeIds;
FilePathIds m_containsMissingIncludes;
BuildDependency &m_buildDependency;
const std::vector<uint> &m_excludedIncludeUID;
std::vector<uint> &m_alreadyIncludedFileUIDs;
bool m_skipInclude = false;

View File

@@ -25,7 +25,7 @@
#pragma once
#include "collectincludesaction.h"
#include "collectbuilddependencyaction.h"
#include <filepathcachingfwd.h>
#include <filepathid.h>
@@ -34,29 +34,17 @@
namespace ClangBackEnd {
class CollectIncludesToolAction final : public clang::tooling::FrontendActionFactory
class CollectBuildDependencyToolAction final : public clang::tooling::FrontendActionFactory
{
public:
CollectIncludesToolAction(FilePathIds &includeIds,
FilePathIds &topIncludeIds,
FilePathIds &topsSystemIncludeIds,
CollectBuildDependencyToolAction(BuildDependency &buildDependency,
const FilePathCachingInterface &filePathCache,
const Utils::PathStringVector &excludedIncludes,
UsedMacros &usedMacros,
SourcesManager &sourcesManager,
SourceDependencies &sourceDependencies,
FilePathIds &sourceFiles,
FileStatuses &fileStatuses)
: m_includeIds(includeIds),
m_topIncludeIds(topIncludeIds),
m_topsSystemIncludeIds(topsSystemIncludeIds),
const ClangBackEnd::FilePaths &excludedIncludes,
SourcesManager &sourcesManager)
: m_buildDependency(buildDependency),
m_filePathCache(filePathCache),
m_excludedIncludes(excludedIncludes),
m_usedMacros(usedMacros),
m_sourcesManager(sourcesManager),
m_sourceDependencies(sourceDependencies),
m_sourceFiles(sourceFiles),
m_fileStatuses(fileStatuses)
m_excludedFilePaths(excludedIncludes),
m_sourcesManager(sourcesManager)
{}
@@ -76,26 +64,21 @@ public:
clang::FrontendAction *create() override
{
return new CollectIncludesAction(m_includeIds,
m_topIncludeIds,
m_topsSystemIncludeIds,
return new CollectBuildDependencyAction(m_buildDependency,
m_filePathCache,
m_excludedIncludeUIDs,
m_alreadyIncludedFileUIDs,
m_usedMacros,
m_sourcesManager,
m_sourceDependencies,
m_sourceFiles,
m_fileStatuses);
m_sourcesManager);
}
std::vector<uint> generateExcludedIncludeFileUIDs(clang::FileManager &fileManager) const
{
std::vector<uint> fileUIDs;
fileUIDs.reserve(m_excludedIncludes.size());
fileUIDs.reserve(m_excludedFilePaths.size());
for (const Utils::PathString &filePath : m_excludedIncludes) {
const clang::FileEntry *file = fileManager.getFile({filePath.data(), filePath.size()}, true);
for (const ClangBackEnd::FilePath &filePath : m_excludedFilePaths) {
const clang::FileEntry *file = fileManager.getFile({filePath.data(), filePath.size()},
true);
if (file)
fileUIDs.push_back(file->getUID());
@@ -109,16 +92,10 @@ public:
private:
std::vector<uint> m_alreadyIncludedFileUIDs;
std::vector<uint> m_excludedIncludeUIDs;
FilePathIds &m_includeIds;
FilePathIds &m_topIncludeIds;
FilePathIds &m_topsSystemIncludeIds;
BuildDependency &m_buildDependency;
const FilePathCachingInterface &m_filePathCache;
const Utils::PathStringVector &m_excludedIncludes;
UsedMacros &m_usedMacros;
const ClangBackEnd::FilePaths &m_excludedFilePaths;
SourcesManager &m_sourcesManager;
SourceDependencies &m_sourceDependencies;
FilePathIds &m_sourceFiles;
FileStatuses &m_fileStatuses;
};
} // namespace ClangBackEnd

View File

@@ -102,7 +102,15 @@ public:
auto includeFilePathId = filePathId(includeLocation);
auto includedFilePathId = filePathId(file);
m_sourceDependencies.emplace_back(includeFilePathId, includedFilePathId);
SourceDependency sourceDependency{includeFilePathId, includedFilePathId};
auto found = std::lower_bound(m_sourceDependencies.begin(),
m_sourceDependencies.end(),
sourceDependency,
[](auto first, auto second) { return first < second; });
if (found == m_sourceDependencies.end() || *found != sourceDependency)
m_sourceDependencies.emplace(found, sourceDependency);
}
void mergeUsedMacros()

View File

@@ -1,103 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "includecollector.h"
#include "collectincludestoolaction.h"
#include <utils/smallstring.h>
#include <algorithm>
namespace ClangBackEnd {
void IncludeCollector::collect()
{
clang::tooling::ClangTool tool = m_clangTool.createTool();
auto action = std::unique_ptr<CollectIncludesToolAction>(
new CollectIncludesToolAction(m_includeIds,
m_topIncludeIds,
m_topsSystemIncludeIds,
m_filePathCache,
m_excludedIncludes,
m_usedMacros,
m_sourcesManager,
m_sourceDependencies,
m_sourceFiles,
m_fileStatuses));
tool.run(action.get());
}
void IncludeCollector::setExcludedIncludes(Utils::PathStringVector &&excludedIncludes)
{
#ifdef _WIN32
m_excludedIncludes.clear();
m_excludedIncludes.reserve(excludedIncludes.size());
std::transform(std::make_move_iterator(excludedIncludes.begin()),
std::make_move_iterator(excludedIncludes.end()),
std::back_inserter(m_excludedIncludes),
[] (Utils::PathString &&path) {
path.replace("/", "\\");
return std::move(path);
});
#else
m_excludedIncludes = std::move(excludedIncludes);
#endif
}
void IncludeCollector::addFiles(const FilePathIds &filePathIds,
const Utils::SmallStringVector &arguments)
{
m_clangTool.addFiles(m_filePathCache.filePaths(filePathIds), arguments);
m_sourceFiles.insert(m_sourceFiles.end(), filePathIds.begin(), filePathIds.end());
}
void IncludeCollector::addFile(FilePathId filePathId, const Utils::SmallStringVector &arguments)
{
addFiles({filePathId}, arguments);
}
void IncludeCollector::addFile(FilePath filePath,
const FilePathIds &sourceFileIds,
const Utils::SmallStringVector &arguments)
{
m_clangTool.addFiles({filePath}, arguments);
m_sourceFiles.insert(m_sourceFiles.end(), sourceFileIds.begin(), sourceFileIds.end());
}
void IncludeCollector::clear()
{
m_clangTool = ClangTool();
m_usedMacros.clear();
m_sourceFiles.clear();
m_fileStatuses.clear();
m_sourceDependencies.clear();
}
} // namespace ClangBackEnd

View File

@@ -26,7 +26,7 @@
#include "pchcreator.h"
#include "environment.h"
#include "includecollector.h"
#include "builddependencycollector.h"
#include "pchnotcreatederror.h"
#include <clangpathwatcherinterface.h>
@@ -58,12 +58,12 @@ void append(Target &target, const Source &source)
target.push_back(ValueType(std::move(entry)));
}
void appendFilePathId(Utils::PathStringVector &target,
void appendFilePathId(ClangBackEnd::FilePaths &target,
const ClangBackEnd::FilePathIds &source,
const ClangBackEnd::FilePathCachingInterface &filePathCache)
{
for (FilePathId id : source)
target.emplace_back(filePathCache.filePath(id).path());
target.emplace_back(filePathCache.filePath(id));
}
Utils::PathStringVector generatedFilePaths(const V2::FileContainers &generaredFiles)
@@ -190,23 +190,23 @@ Utils::PathStringVector PchCreator::generateProjectPartHeaders(
namespace {
std::size_t sizeOfContent(const Utils::PathStringVector &paths)
std::size_t sizeOfContent(const ClangBackEnd::FilePaths &paths)
{
return std::accumulate(paths.begin(),
paths.end(),
std::size_t(0),
[] (std::size_t size, const Utils::PathString &path) {
[] (std::size_t size, const auto &path) {
const char includeTemplate[] = "#include \"\"\n";
return size + path.size() + sizeof(includeTemplate);
});
}
Utils::SmallString concatContent(const Utils::PathStringVector &paths, std::size_t size)
Utils::SmallString concatContent(const ClangBackEnd::FilePaths &paths, std::size_t size)
{
Utils::SmallString content;
content.reserve(size);
for (const Utils::PathString &path : paths) {
for (const ClangBackEnd::FilePath &path : paths) {
content += "#include \"";
content += path;
content += "\"\n";
@@ -220,15 +220,15 @@ Utils::SmallString concatContent(const Utils::PathStringVector &paths, std::size
Utils::SmallString PchCreator::generateProjectPartSourcesContent(
const V2::ProjectPartContainer &projectPart) const
{
Utils::PathStringVector paths = generateProjectPartSourcePaths(projectPart);
ClangBackEnd::FilePaths paths = generateProjectPartSourcePaths(projectPart);
return concatContent(paths, sizeOfContent(paths));
}
Utils::PathStringVector PchCreator::generateProjectPartSourcePaths(
ClangBackEnd::FilePaths PchCreator::generateProjectPartSourcePaths(
const V2::ProjectPartContainer &projectPart) const
{
Utils::PathStringVector includeAndSources;
ClangBackEnd::FilePaths includeAndSources;
includeAndSources.reserve(projectPart.sourcePathIds.size());
appendFilePathId(includeAndSources, projectPart.sourcePathIds, m_filePathCache);
@@ -236,7 +236,7 @@ Utils::PathStringVector PchCreator::generateProjectPartSourcePaths(
return includeAndSources;
}
PchCreatorIncludes PchCreator::generateProjectPartPchIncludes(
SourceEntries PchCreator::generateProjectPartPchIncludes(
const V2::ProjectPartContainer &projectPart) const
{
Utils::SmallString jointedFileContent = generateProjectPartSourcesContent(projectPart);
@@ -245,9 +245,9 @@ PchCreatorIncludes PchCreator::generateProjectPartPchIncludes(
Utils::SmallStringVector arguments = generateProjectPartCommandLine(projectPart);
FilePath filePath{Utils::PathString(jointedFilePath)};
IncludeCollector collector(m_filePathCache);
BuildDependencyCollector collector(m_filePathCache);
collector.setExcludedIncludes(generateProjectPartSourcePaths(projectPart));
collector.setExcludedFilePaths(generateProjectPartSourcePaths(projectPart));
collector.addFile(filePath, projectPart.sourcePathIds, arguments);
@@ -257,7 +257,7 @@ PchCreatorIncludes PchCreator::generateProjectPartPchIncludes(
jointFile->remove();
return {collector.takeIncludeIds(), collector.takeTopIncludeIds(), collector.takeTopsSystemIncludeIds()};
return collector.includeIds();
}
Utils::SmallString PchCreator::generateProjectPathPchHeaderFilePath(
@@ -309,7 +309,7 @@ IdPaths PchCreator::generateProjectPartPch(const V2::ProjectPartContainer &proje
{
long long lastModified = QDateTime::currentSecsSinceEpoch();
auto includes = generateProjectPartPchIncludes(projectPart);
auto content = generatePchIncludeFileContent(includes.topIncludeIds);
auto content = generatePchIncludeFileContent(topIncludeIds(includes));
auto pchIncludeFilePath = generateProjectPathPchHeaderFilePath(projectPart);
auto pchFilePath = generateProjectPartPchFilePath(projectPart);
generateFileWithContent(pchIncludeFilePath, content);
@@ -323,7 +323,7 @@ IdPaths PchCreator::generateProjectPartPch(const V2::ProjectPartContainer &proje
m_projectPartPch.lastModified = lastModified;
}
return {projectPart.projectPartId.clone(), std::move(includes.includeIds)};
return {projectPart.projectPartId.clone(), allIncludeIds(includes)};
}
void PchCreator::generatePch(const V2::ProjectPartContainer &projectPart)
@@ -392,6 +392,32 @@ std::unique_ptr<QFile> PchCreator::generateFileWithContent(
return precompiledIncludeFile;
}
FilePathIds PchCreator::topIncludeIds(const SourceEntries &includes)
{
FilePathIds topIncludes;
topIncludes.reserve(includes.size());
for (SourceEntry include : includes) {
if (include.sourceType == SourceType::TopInclude)
topIncludes.push_back(include.sourceId);
}
return topIncludes;
}
FilePathIds PchCreator::allIncludeIds(const SourceEntries &includes)
{
FilePathIds allIncludes;
allIncludes.reserve(includes.size());
std::transform(includes.begin(),
includes.end(),
std::back_inserter(allIncludes),
[](auto &&entry) { return entry.sourceId; });
return allIncludes;
}
QByteArray PchCreator::projectPartHash(const V2::ProjectPartContainer &projectPart)
{
QCryptographicHash hash(QCryptographicHash::Sha1);

View File

@@ -28,6 +28,7 @@
#include "pchcreatorinterface.h"
#include "idpaths.h"
#include "sourceentry.h"
#include <filepathcaching.h>
#include <projectpartpch.h>
@@ -93,9 +94,9 @@ public:
const V2::ProjectPartContainer &projectPart) const;
Utils::SmallString generateProjectPartSourcesContent(
const V2::ProjectPartContainer &projectPart) const;
Utils::PathStringVector generateProjectPartSourcePaths(
ClangBackEnd::FilePaths generateProjectPartSourcePaths(
const V2::ProjectPartContainer &projectPart) const;
PchCreatorIncludes generateProjectPartPchIncludes(
SourceEntries generateProjectPartPchIncludes(
const V2::ProjectPartContainer &projectPart) const;
Utils::SmallString generateProjectPathPchHeaderFilePath(
const V2::ProjectPartContainer &projectPart) const;
@@ -113,6 +114,9 @@ public:
const Utils::SmallString &filePath,
const Utils::SmallString &content);
static FilePathIds topIncludeIds(const SourceEntries &includes);
static FilePathIds allIncludeIds(const SourceEntries &includes);
private:
static QByteArray projectPartHash(const V2::ProjectPartContainer &projectPart);

View File

@@ -33,9 +33,10 @@ namespace ClangBackEnd {
enum class SourceType : unsigned char
{
Any,
TopInclude,
TopSystemInclude
TopSystemInclude,
UserInclude,
SystemInclude
};
class TimeStamp
@@ -62,7 +63,6 @@ public:
: lastModified(lastModified),
sourceId(sourceId),
sourceType(static_cast<SourceType>(sourceType))
{}
SourceEntry(FilePathId sourceId, SourceType sourceType, TimeStamp lastModified)
@@ -85,10 +85,12 @@ public:
&& first.lastModified == second.lastModified ;
}
friend bool operator!=(SourceEntry first, SourceEntry second) { return !(first == second); }
public:
TimeStamp lastModified;
FilePathId sourceId;
SourceType sourceType = SourceType::Any;
SourceType sourceType = SourceType::UserInclude;
};
using SourceEntries = std::vector<SourceEntry>;

View File

@@ -135,6 +135,8 @@ clang::tooling::ClangTool ClangTool::createTool() const
tool.mapVirtualFile(toStringRef(unsavedFileContent.filePath),
toStringRef(unsavedFileContent.content));
tool.mapVirtualFile("/dummyFile", "#pragma once");
return tool;
}

View File

@@ -54,6 +54,12 @@ public:
&& first.lastModified == second.lastModified;
}
friend
bool operator<(const FileStatus &first, const FileStatus &second)
{
return first.filePathId < second.filePathId;
}
public:
FilePathId filePathId;
off_t size;

View File

@@ -34,23 +34,32 @@ namespace ClangBackEnd {
class SourceDependency
{
public:
SourceDependency(FilePathId filePathId,
FilePathId dependencyFilePathId)
: filePathId(filePathId),
dependencyFilePathId(dependencyFilePathId)
SourceDependency(FilePathId filePathId, FilePathId dependencyFilePathId)
: filePathId(filePathId)
, dependencyFilePathId(dependencyFilePathId)
{}
friend
bool operator==(SourceDependency first, SourceDependency second)
friend bool operator==(SourceDependency first, SourceDependency second)
{
return first.filePathId == second.filePathId
&& first.dependencyFilePathId == second.dependencyFilePathId;
}
friend bool operator!=(SourceDependency first, SourceDependency second)
{
return !(first == second);
}
friend bool operator<(SourceDependency first, SourceDependency second)
{
return std::tie(first.filePathId, first.dependencyFilePathId)
< std::tie(second.filePathId, second.dependencyFilePathId);
}
public:
FilePathId filePathId;
FilePathId dependencyFilePathId;
};
using SourceDependencies = std::vector<SourceDependency>;
}
} // namespace ClangBackEnd

View File

@@ -145,7 +145,7 @@ public:
return SymbolIndex(reinterpret_cast<std::uintptr_t>(pointer));
}
void setSourceManager(const clang::SourceManager *sourceManager)
void setSourceManager(clang::SourceManager *sourceManager)
{
m_sourceManager = sourceManager;
}

View File

@@ -27,7 +27,7 @@
#include "mockbuilddependenciesstorage.h"
#include "mockmodifiedtimechecker.h"
#include "mockbuilddependenciesgenerator.h"
#include "mockbuilddependencygenerator.h"
#include <builddependenciesprovider.h>
@@ -56,7 +56,7 @@ class BuildDependenciesProvider : public testing::Test
protected:
NiceMock<MockBuildDependenciesStorage> mockBuildDependenciesStorage;
NiceMock<MockModifiedTimeChecker> mockModifiedTimeChecker;
NiceMock<MockBuildDependenciesGenerator> mockBuildDependenciesGenerator;
NiceMock<MockBuildDependencyGenerator> mockBuildDependenciesGenerator;
ClangBackEnd::BuildDependenciesProvider provider{mockBuildDependenciesStorage, mockModifiedTimeChecker, mockBuildDependenciesGenerator};
ClangBackEnd::V2::ProjectPartContainer projectPart1{"ProjectPart1",
{"--yi"},
@@ -70,13 +70,13 @@ protected:
{"/er"},
{1},
{2, 3, 4}};
SourceEntries firstSources{{1, SourceType::Any, 1}, {2, SourceType::Any, 1}, {10, SourceType::Any, 1}};
SourceEntries secondSources{{1, SourceType::Any, 1}, {3, SourceType::Any, 1}, {8, SourceType::Any, 1}};
SourceEntries thirdSources{{4, SourceType::Any, 1}, {8, SourceType::Any, 1}, {10, SourceType::Any, 1}};
SourceEntries firstSources{{1, SourceType::UserInclude, 1}, {2, SourceType::UserInclude, 1}, {10, SourceType::UserInclude, 1}};
SourceEntries secondSources{{1, SourceType::UserInclude, 1}, {3, SourceType::UserInclude, 1}, {8, SourceType::UserInclude, 1}};
SourceEntries thirdSources{{4, SourceType::UserInclude, 1}, {8, SourceType::UserInclude, 1}, {10, SourceType::UserInclude, 1}};
UsedMacros firstUsedMacros{{"YI", 1}};
UsedMacros secondUsedMacros{{"LIANG", 2}, {"ER", 2}};
UsedMacros thirdUsedMacros{{"SAN", 10}};
BuildDependency buildDependency{secondSources, {}, {}, {}};
BuildDependency buildDependency{secondSources, {}};
};
TEST_F(BuildDependenciesProvider, CreateCallsFetchDependSourcesFromStorageIfTimeStampsAreUpToDate)

View File

@@ -171,9 +171,9 @@ TEST_F(BuildDependenciesStorage, UpdateSources)
SourceEntries entries{{1, SourceType::TopInclude, 10}, {2, SourceType::TopSystemInclude, 20}};
EXPECT_CALL(updateBuildDependencyTimeStampStatement, write(TypedEq<long long>(10), TypedEq<int>(1)));
EXPECT_CALL(updateSourceTypeStatement, write(TypedEq<uchar>(1), TypedEq<int>(1)));
EXPECT_CALL(updateSourceTypeStatement, write(TypedEq<uchar>(0), TypedEq<int>(1)));
EXPECT_CALL(updateBuildDependencyTimeStampStatement, write(TypedEq<long long>(20), TypedEq<int>(2)));
EXPECT_CALL(updateSourceTypeStatement, write(TypedEq<uchar>(2), TypedEq<int>(2)));
EXPECT_CALL(updateSourceTypeStatement, write(TypedEq<uchar>(1), TypedEq<int>(2)));
storage.updateSources(entries);
}

View File

@@ -0,0 +1,635 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "googletest.h"
#include <refactoringdatabaseinitializer.h>
#include <filepathcaching.h>
#include <builddependencycollector.h>
#include <sqlitedatabase.h>
#include <QDateTime>
#include <QDir>
using testing::AllOf;
using testing::Contains;
using testing::Not;
using testing::ElementsAre;
using testing::UnorderedElementsAre;
using ClangBackEnd::BuildDependency;
using ClangBackEnd::FilePathId;
using ClangBackEnd::FilePathIds;
using ClangBackEnd::FilePathView;
using ClangBackEnd::SourceDependency;
using ClangBackEnd::SourceType;
using ClangBackEnd::UsedMacro;
namespace {
MATCHER_P2(HasInclude, sourceId, sourceType,
std::string(negation ? "hasn't " : "has ")
+ PrintToString(ClangBackEnd::SourceEntry(sourceId, sourceType, -1)))
{
const ClangBackEnd::SourceEntry &entry = arg;
return entry.sourceId == sourceId && entry.sourceType == sourceType;
}
class BuildDependencyCollector : public ::testing::Test
{
protected:
BuildDependencyCollector()
{
setFilePathCache(&filePathCache);
collector.addFile(id(TESTDATA_DIR "/builddependencycollector/project/main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
collector.addFile(id(TESTDATA_DIR "/builddependencycollector/project/main2.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
collector.addUnsavedFiles({{{TESTDATA_DIR, "BuildDependencyCollector/project/generated_file.h"}, "#pragma once", {}}});
collector.setExcludedFilePaths(Utils::clone(excludePaths));
emptyCollector.setExcludedFilePaths(Utils::clone(excludePaths));
}
~BuildDependencyCollector()
{
setFilePathCache(nullptr);
}
FilePathId id(const Utils::SmallStringView &path) const
{
return filePathCache.filePathId(FilePathView{path});
}
static off_t fileSize(Utils::SmallStringView filePath)
{
return QFileInfo(QString(filePath)).size();
}
static std::time_t lastModified(Utils::SmallStringView filePath)
{
return QFileInfo(QString(filePath)).lastModified().toTime_t();
}
ClangBackEnd::FileStatus fileStatus(Utils::SmallStringView filePath) const
{
return {id(filePath), fileSize(filePath), lastModified(filePath), false};
}
static
FilePathIds filteredIncludes(const ClangBackEnd::SourceEntries &includes,
ClangBackEnd::SourceType includeType)
{
FilePathIds filteredIncludes;
for (const ClangBackEnd::SourceEntry &include : includes) {
if (include.sourceType == includeType)
filteredIncludes.push_back(include.sourceId);
}
return filteredIncludes;
}
static
FilePathIds topIncludes(const ClangBackEnd::SourceEntries &includes)
{
return filteredIncludes(includes, ClangBackEnd::SourceType::TopInclude);
}
static
FilePathIds systemTopIncludes(const ClangBackEnd::SourceEntries &includes)
{
return filteredIncludes(includes, ClangBackEnd::SourceType::TopSystemInclude);
}
static
FilePathIds userIncludes(const ClangBackEnd::SourceEntries &includes)
{
return filteredIncludes(includes, ClangBackEnd::SourceType::UserInclude);
}
static
FilePathIds allIncludes(const ClangBackEnd::SourceEntries &includes)
{
FilePathIds filteredIncludes;
for (const ClangBackEnd::SourceEntry &include : includes)
filteredIncludes.push_back(include.sourceId);
return filteredIncludes;
}
protected:
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database};
ClangBackEnd::FilePathCaching filePathCache{database};
ClangBackEnd::BuildDependencyCollector collector{filePathCache};
ClangBackEnd::BuildDependencyCollector emptyCollector{filePathCache};
ClangBackEnd::FilePaths excludePaths = {TESTDATA_DIR "/builddependencycollector/project/main.cpp",
TESTDATA_DIR "/builddependencycollector/project/main2.cpp",
TESTDATA_DIR "/builddependencycollector/project/header1.h",
TESTDATA_DIR "/builddependencycollector/project/header2.h",
TESTDATA_DIR "/builddependencycollector/project/generated_file.h"};
};
TEST_F(BuildDependencyCollector, IncludesExternalHeader)
{
collector.collect();
ASSERT_THAT(allIncludes(collector.includeIds()),
AllOf(Contains(id(TESTDATA_DIR "/builddependencycollector/external/external1.h")),
Contains(id(TESTDATA_DIR "/builddependencycollector/external/external2.h")),
Contains(id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h")),
Contains(id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h"))));
}
TEST_F(BuildDependencyCollector, InternalHeaderAreUserIncludes)
{
collector.collect();
ASSERT_THAT(userIncludes(collector.includeIds()), Contains(id(TESTDATA_DIR "/builddependencycollector/project/header1.h")));
}
TEST_F(BuildDependencyCollector, NoDuplicate)
{
collector.collect();
ASSERT_THAT(allIncludes(collector.includeIds()),
UnorderedElementsAre(
id(TESTDATA_DIR "/builddependencycollector/project/header1.h"),
id(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external2.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external3.h"),
id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h"),
id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h")));
}
TEST_F(BuildDependencyCollector, IncludesAreSorted)
{
collector.collect();
ASSERT_THAT(allIncludes(collector.includeIds()),
ElementsAre(
id(TESTDATA_DIR "/builddependencycollector/project/header1.h"),
id(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external3.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h"),
id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external2.h")));
}
TEST_F(BuildDependencyCollector, If)
{
emptyCollector.addFile(id(TESTDATA_DIR "/builddependencycollector/project/if.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.collect();
ASSERT_THAT(allIncludes(emptyCollector.includeIds()),
ElementsAre(id(TESTDATA_DIR "/builddependencycollector/project/true.h")));
}
TEST_F(BuildDependencyCollector, LocalPath)
{
emptyCollector.addFile(id(TESTDATA_DIR "/builddependencycollector/project/main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.collect();
ASSERT_THAT(allIncludes(emptyCollector.includeIds()),
UnorderedElementsAre(
id(TESTDATA_DIR "/builddependencycollector/project/header1.h"),
id(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external2.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external3.h"),
id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h"),
id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h")));
}
TEST_F(BuildDependencyCollector, IgnoreMissingFile)
{
emptyCollector.addFile(id(TESTDATA_DIR "/builddependencycollector/project/missingfile.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.collect();
ASSERT_THAT(allIncludes(emptyCollector.includeIds()),
UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h"),
id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h")));
}
TEST_F(BuildDependencyCollector, IncludesOnlyTopExternalHeader)
{
collector.collect();
ASSERT_THAT(topIncludes(collector.includeIds()),
UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external2.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external3.h")));
}
TEST_F(BuildDependencyCollector, TopIncludeInIfMacro)
{
emptyCollector.addFile(id(TESTDATA_DIR "/builddependencycollector/project/if.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.setExcludedFilePaths({TESTDATA_DIR "/builddependencycollector/project/if.cpp"});
emptyCollector.collect();
ASSERT_THAT(topIncludes(emptyCollector.includeIds()),
ElementsAre(id(TESTDATA_DIR "/builddependencycollector/project/true.h")));
}
TEST_F(BuildDependencyCollector, TopIncludeWithLocalPath)
{
emptyCollector.addFile(id(TESTDATA_DIR "/builddependencycollector/project/main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.collect();
ASSERT_THAT(topIncludes(emptyCollector.includeIds()),
UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external2.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external3.h")));
}
TEST_F(BuildDependencyCollector, TopIncludesIgnoreMissingFile)
{
emptyCollector.addFile(id(TESTDATA_DIR "/builddependencycollector/project/missingfile.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.setExcludedFilePaths({TESTDATA_DIR "/builddependencycollector/project/missingfile.cpp"});
emptyCollector.collect();
ASSERT_THAT(topIncludes(emptyCollector.includeIds()),
UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h")));
}
TEST_F(BuildDependencyCollector, SourceFiles)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.sourceFiles(),
UnorderedElementsAre(id(TESTDATA_DIR "/symbolscollector_main.cpp"),
id(TESTDATA_DIR "/symbolscollector_header1.h"),
id(TESTDATA_DIR "/symbolscollector_header2.h")));
}
TEST_F(BuildDependencyCollector, MainFileInSourceFiles)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
ASSERT_THAT(emptyCollector.sourceFiles(),
ElementsAre(id(TESTDATA_DIR "/symbolscollector_main.cpp")));
}
TEST_F(BuildDependencyCollector, ResetMainFileInSourceFiles)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
ASSERT_THAT(emptyCollector.sourceFiles(),
ElementsAre(id(TESTDATA_DIR "/symbolscollector_main.cpp")));
}
TEST_F(BuildDependencyCollector, DontDuplicateSourceFiles)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.collect();
emptyCollector.collect();
ASSERT_THAT(emptyCollector.sourceFiles(),
UnorderedElementsAre(id(TESTDATA_DIR "/symbolscollector_main.cpp"),
id(TESTDATA_DIR "/symbolscollector_header1.h"),
id(TESTDATA_DIR "/symbolscollector_header2.h")));
}
TEST_F(BuildDependencyCollector, ClearSourceFiles)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.clear();
ASSERT_THAT(emptyCollector.sourceFiles(), IsEmpty());
}
TEST_F(BuildDependencyCollector, ClearFileStatus)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.collect();
emptyCollector.clear();
ASSERT_THAT(emptyCollector.fileStatuses(), IsEmpty());
}
TEST_F(BuildDependencyCollector, ClearUsedMacros)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_defines.h"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.collect();
emptyCollector.clear();
ASSERT_THAT(emptyCollector.usedMacros(), IsEmpty());
}
TEST_F(BuildDependencyCollector, ClearSourceDependencies)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main2.cpp"), {"cc", "-I" TESTDATA_DIR});
emptyCollector.collect();
emptyCollector.clear();
ASSERT_THAT(emptyCollector.sourceDependencies(), IsEmpty());
}
TEST_F(BuildDependencyCollector, DontCollectSourceFilesAfterFilesAreCleared)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.clear();
emptyCollector.collect();
ASSERT_THAT(emptyCollector.sourceFiles(), IsEmpty());
}
TEST_F(BuildDependencyCollector, DontCollectFileStatusAfterFilesAreCleared)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.clear();
emptyCollector.collect();
ASSERT_THAT(emptyCollector.fileStatuses(), IsEmpty());
}
TEST_F(BuildDependencyCollector, DontCollectUsedMacrosAfterFilesAreCleared)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.clear();
emptyCollector.collect();
ASSERT_THAT(emptyCollector.usedMacros(), IsEmpty());
}
TEST_F(BuildDependencyCollector, DontCollectSourceDependenciesAfterFilesAreCleared)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.clear();
emptyCollector.collect();
ASSERT_THAT(emptyCollector.sourceDependencies(), IsEmpty());
}
TEST_F(BuildDependencyCollector, CollectUsedMacrosWithExternalDefine)
{
auto fileId = id(TESTDATA_DIR "/symbolscollector_defines.h");
emptyCollector.addFile(fileId, {"cc", "-DCOMPILER_ARGUMENT"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.usedMacros(),
ElementsAre(Eq(UsedMacro{"DEFINED", fileId}),
Eq(UsedMacro{"IF_DEFINE", fileId}),
Eq(UsedMacro{"__clang__", fileId}),
Eq(UsedMacro{"CLASS_EXPORT", fileId}),
Eq(UsedMacro{"IF_NOT_DEFINE", fileId}),
Eq(UsedMacro{"MACRO_EXPANSION", fileId}),
Eq(UsedMacro{"COMPILER_ARGUMENT", fileId})));
}
TEST_F(BuildDependencyCollector, CollectUsedMacrosWithoutExternalDefine)
{
auto fileId = id(TESTDATA_DIR "/symbolscollector_defines.h");
emptyCollector.addFile(fileId, {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.usedMacros(),
ElementsAre(Eq(UsedMacro{"DEFINED", fileId}),
Eq(UsedMacro{"IF_DEFINE", fileId}),
Eq(UsedMacro{"__clang__", fileId}),
Eq(UsedMacro{"CLASS_EXPORT", fileId}),
Eq(UsedMacro{"IF_NOT_DEFINE", fileId}),
Eq(UsedMacro{"MACRO_EXPANSION", fileId}),
Eq(UsedMacro{"COMPILER_ARGUMENT", fileId})));
}
TEST_F(BuildDependencyCollector, DontCollectHeaderGuards)
{
auto fileId = id(TESTDATA_DIR "/symbolscollector_defines.h");
emptyCollector.addFile(fileId, {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.usedMacros(),
Not(Contains(Eq(UsedMacro{"SYMBOLSCOLLECTOR_DEFINES_H", fileId}))));
}
TEST_F(BuildDependencyCollector, DISABLED_DontCollectDynamicLibraryExports)
{
auto fileId = id(TESTDATA_DIR "/symbolscollector_defines.h");
emptyCollector.addFile(fileId, {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.usedMacros(),
Not(Contains(Eq(UsedMacro{"CLASS_EXPORT", fileId}))));
}
TEST_F(BuildDependencyCollector, CollectFileStatuses)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.fileStatuses(),
ElementsAre(
fileStatus(TESTDATA_DIR "/symbolscollector_main.cpp"),
fileStatus(TESTDATA_DIR "/symbolscollector_header1.h"),
fileStatus(TESTDATA_DIR "/symbolscollector_header2.h")));
}
TEST_F(BuildDependencyCollector, CollectSourceDependencies)
{
auto mainFileId = id(TESTDATA_DIR "/symbolscollector_main2.cpp");
auto header1FileId = id(TESTDATA_DIR "/symbolscollector_header1.h");
auto header2FileId = id(TESTDATA_DIR "/symbolscollector_header2.h");
auto header3FileId = id(TESTDATA_DIR "/symbolscollector_header3.h");
emptyCollector.addFile(mainFileId, {"cc", "-I" TESTDATA_DIR});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.sourceDependencies(),
UnorderedElementsAre(SourceDependency(mainFileId, header1FileId),
SourceDependency(mainFileId, header3FileId),
SourceDependency(header3FileId, header2FileId),
SourceDependency(header1FileId, header2FileId)));
}
TEST_F(BuildDependencyCollector, Create)
{
ClangBackEnd::BuildDependencyCollector collector{filePathCache};
ClangBackEnd::V2::ProjectPartContainer
projectPart{"project1",
{"cc",
"-I",
TESTDATA_DIR "/builddependencycollector/external",
"-I",
TESTDATA_DIR "/builddependencycollector/project",
"-isystem",
TESTDATA_DIR "/builddependencycollector/system"},
{},
{},
{id(TESTDATA_DIR "/builddependencycollector/project/header1.h"),
id(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
id(TESTDATA_DIR "/builddependencycollector/project/missingfile.h"),
id(TESTDATA_DIR "/builddependencycollector/project/macros.h"),},
{id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp")}};
auto buildDependency = collector.create(projectPart);
ASSERT_THAT(
buildDependency,
AllOf(
Field(&BuildDependency::fileStatuses,
UnorderedElementsAre(
fileStatus(TESTDATA_DIR "/builddependencycollector/project/main4.cpp"),
fileStatus(TESTDATA_DIR "/builddependencycollector/project/header1.h"),
fileStatus(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
fileStatus(TESTDATA_DIR "/builddependencycollector/external/external3.h"),
fileStatus(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
fileStatus(TESTDATA_DIR
"/builddependencycollector/external/indirect_external.h"),
fileStatus(TESTDATA_DIR
"/builddependencycollector/external/indirect_external2.h"),
fileStatus(TESTDATA_DIR "/builddependencycollector/external/external2.h"),
fileStatus(TESTDATA_DIR "/builddependencycollector/system/system1.h"),
fileStatus(TESTDATA_DIR "/builddependencycollector/system/indirect_system.h"),
fileStatus(TESTDATA_DIR "/builddependencycollector/system/indirect_system2.h"),
fileStatus(TESTDATA_DIR "/builddependencycollector/project/missingfile.h"),
fileStatus(TESTDATA_DIR "/builddependencycollector/project/macros.h"))),
Field(&BuildDependency::includes,
UnorderedElementsAre(
HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"),
SourceType::UserInclude),
HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
SourceType::UserInclude),
HasInclude(id(TESTDATA_DIR "/builddependencycollector/external/external3.h"),
SourceType::TopInclude),
HasInclude(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
SourceType::TopInclude),
HasInclude(id(TESTDATA_DIR
"/builddependencycollector/external/indirect_external.h"),
SourceType::UserInclude),
HasInclude(id(TESTDATA_DIR
"/builddependencycollector/external/indirect_external2.h"),
SourceType::UserInclude),
HasInclude(id(TESTDATA_DIR "/builddependencycollector/external/external2.h"),
SourceType::TopInclude),
HasInclude(id(TESTDATA_DIR "/builddependencycollector/system/system1.h"),
SourceType::TopSystemInclude),
HasInclude(id(TESTDATA_DIR
"/builddependencycollector/system/indirect_system.h"),
SourceType::SystemInclude),
HasInclude(id(TESTDATA_DIR
"/builddependencycollector/system/indirect_system2.h"),
SourceType::SystemInclude),
HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/missingfile.h"),
SourceType::UserInclude),
HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/macros.h"),
SourceType::UserInclude))),
Field(&BuildDependency::usedMacros,
UnorderedElementsAre(
UsedMacro{"DEFINE",
id(TESTDATA_DIR "/builddependencycollector/project/macros.h")},
UsedMacro{"IFDEF",
id(TESTDATA_DIR "/builddependencycollector/project/macros.h")},
UsedMacro{"DEFINED",
id(TESTDATA_DIR "/builddependencycollector/project/macros.h")})),
Field(&BuildDependency::sourceFiles,
UnorderedElementsAre(
id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp"),
id(TESTDATA_DIR "/builddependencycollector/project/header1.h"),
id(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external3.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h"),
id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external2.h"),
id(TESTDATA_DIR "/builddependencycollector/system/system1.h"),
id(TESTDATA_DIR "/builddependencycollector/system/indirect_system.h"),
id(TESTDATA_DIR "/builddependencycollector/system/indirect_system2.h"),
id(TESTDATA_DIR "/builddependencycollector/project/missingfile.h"),
id(TESTDATA_DIR "/builddependencycollector/project/macros.h"))),
Field(
&BuildDependency::sourceDependencies,
UnorderedElementsAre(
SourceDependency(id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp"),
id(TESTDATA_DIR "/builddependencycollector/project/header1.h")),
SourceDependency(id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp"),
id(TESTDATA_DIR "/builddependencycollector/project/header2.h")),
SourceDependency(id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp"),
id(TESTDATA_DIR
"/builddependencycollector/project/missingfile.h")),
SourceDependency(id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp"),
id(TESTDATA_DIR
"/builddependencycollector/external/external1.h")),
SourceDependency(id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp"),
id(TESTDATA_DIR
"/builddependencycollector/external/external2.h")),
SourceDependency(id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp"),
id(TESTDATA_DIR "/builddependencycollector/system/system1.h")),
SourceDependency(id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp"),
id(TESTDATA_DIR "/builddependencycollector/project/macros.h")),
SourceDependency(id(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
id(TESTDATA_DIR
"/builddependencycollector/external/external3.h")),
SourceDependency(id(TESTDATA_DIR
"/builddependencycollector/project/missingfile.h"),
id(TESTDATA_DIR
"/builddependencycollector/external/external1.h")),
SourceDependency(id(TESTDATA_DIR
"/builddependencycollector/external/external1.h"),
id(TESTDATA_DIR
"/builddependencycollector/external/indirect_external.h")),
SourceDependency(id(TESTDATA_DIR
"/builddependencycollector/external/indirect_external.h"),
id(TESTDATA_DIR
"/builddependencycollector/external/indirect_external2.h")),
SourceDependency(id(TESTDATA_DIR "/builddependencycollector/system/system1.h"),
id(TESTDATA_DIR
"/builddependencycollector/system/indirect_system.h")),
SourceDependency(id(TESTDATA_DIR
"/builddependencycollector/system/indirect_system.h"),
id(TESTDATA_DIR
"/builddependencycollector/system/indirect_system2.h"))))));
}
} // namespace

View File

@@ -0,0 +1,11 @@
#pragma once
#define DEFINE
#ifdef IFDEF
#endif
#if defined(DEFINED)
#endif
DEFINE

View File

@@ -0,0 +1,9 @@
#include <header1.h>
#include <header2.h>
#include "missingfile.h"
#include "missingfile.h"
#include <external1.h>
#include <../external/external1.h>
#include <../external/external2.h>
#include <system1.h>
#include "macros.h"

View File

@@ -0,0 +1,8 @@
#pragma once
#include "missing_file.moc"
#include "foo/missing_file.moc"
#include <missing_file2.moc>
#include <foo2/missing_file2.moc>
#include "external1.h"

View File

@@ -66,6 +66,10 @@
#include <coreplugin/find/searchresultitem.h>
#include <coreplugin/locator/ilocatorfilter.h>
namespace {
ClangBackEnd::FilePathCaching *filePathCache = nullptr;
}
void PrintTo(const Utf8String &text, ::std::ostream *os)
{
*os << text;
@@ -171,7 +175,10 @@ namespace ClangBackEnd {
std::ostream &operator<<(std::ostream &out, const FilePathId &id)
{
return out << "(" << id.filePathId << ")";
if (filePathCache)
return out << "(" << id.filePathId << ", " << filePathCache->filePath(id) << ")";
return out << id.filePathId;
}
std::ostream &operator<<(std::ostream &out, const FilePathView &filePathView)
@@ -1014,10 +1021,13 @@ std::ostream &operator<<(std::ostream &out, const PchTask &task)
std::ostream &operator<<(std::ostream &out, const BuildDependency &dependency)
{
return out << "("
<< dependency.includes << ", "
<< dependency.topsSystemIncludeIds << ", "
<< dependency.topIncludeIds << ")";
return out << "(\n"
<< "includes: " << dependency.includes << ",\n"
<< "usedMacros: " << dependency.usedMacros << ",\n"
<< "fileStatuses: " << dependency.fileStatuses << ",\n"
<< "sourceFiles: " << dependency.sourceFiles << ",\n"
<< "sourceDependencies: " << dependency.sourceDependencies << ",\n"
<< ")";
}
const char *sourceTypeString(SourceType sourceType)
@@ -1025,9 +1035,14 @@ const char *sourceTypeString(SourceType sourceType)
using ClangBackEnd::SymbolTag;
switch (sourceType) {
case SourceType::Any: return "Any";
case SourceType::TopInclude: return "TopInclude";
case SourceType::TopSystemInclude: return "TopSystemInclude";
case SourceType::TopInclude:
return "TopInclude";
case SourceType::TopSystemInclude:
return "TopSystemInclude";
case SourceType::SystemInclude:
return "SystemInclude";
case SourceType::UserInclude:
return "UserInclude";
}
return "";
@@ -1131,3 +1146,8 @@ std::ostream &operator<<(std::ostream &out, const Usage &usage)
return out << "(" << usage.path << ", " << usage.line << ", " << usage.column <<")";
}
} // namespace CppTools
void setFilePathCache(ClangBackEnd::FilePathCaching *cache)
{
filePathCache = cache;
}

View File

@@ -173,6 +173,7 @@ class PchCreatorIncludes;
class PchTask;
class BuildDependency;
class SourceEntry;
class FilePathCaching;
std::ostream &operator<<(std::ostream &out, const SourceLocationEntry &entry);
std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths);
@@ -289,3 +290,5 @@ class Usage;
std::ostream &operator<<(std::ostream &out, const Usage &usage);
} // namespace CppTools
void setFilePathCache(ClangBackEnd::FilePathCaching *filePathCache);

View File

@@ -1,422 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "googletest.h"
#include <refactoringdatabaseinitializer.h>
#include <filepathcaching.h>
#include <includecollector.h>
#include <sqlitedatabase.h>
#include <QDateTime>
#include <QDir>
using testing::AllOf;
using testing::Contains;
using testing::Not;
using testing::ElementsAre;
using testing::UnorderedElementsAre;
using ClangBackEnd::FilePathId;
using ClangBackEnd::FilePathIds;
using ClangBackEnd::FilePathView;
using ClangBackEnd::SourceDependency;
using ClangBackEnd::UsedMacro;
namespace {
class IncludeCollector : public ::testing::Test
{
protected:
void SetUp()
{
collector.addFile(id(TESTDATA_DIR "/includecollector/project/main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
collector.addFile(id(TESTDATA_DIR "/includecollector/project/main2.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
collector.addUnsavedFiles({{{TESTDATA_DIR, "includecollector/project/generated_file.h"}, "#pragma once", {}}});
collector.setExcludedIncludes(excludePaths.clone());
emptyCollector.setExcludedIncludes(excludePaths.clone());
}
FilePathId id(const Utils::SmallStringView &path) const
{
return filePathCache.filePathId(FilePathView{path});
}
static off_t fileSize(Utils::SmallStringView filePath)
{
return QFileInfo(QString(filePath)).size();
}
static std::time_t lastModified(Utils::SmallStringView filePath)
{
return QFileInfo(QString(filePath)).lastModified().toTime_t();
}
ClangBackEnd::FileStatus fileStatus(Utils::SmallStringView filePath) const
{
return {id(filePath), fileSize(filePath), lastModified(filePath), false};
}
protected:
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database};
ClangBackEnd::FilePathCaching filePathCache{database};
ClangBackEnd::IncludeCollector collector{filePathCache};
ClangBackEnd::IncludeCollector emptyCollector{filePathCache};
Utils::PathStringVector excludePaths = {TESTDATA_DIR "/includecollector/project/main.cpp",
TESTDATA_DIR "/includecollector/project/main2.cpp",
TESTDATA_DIR "/includecollector/project/header1.h",
TESTDATA_DIR "/includecollector/project/header2.h",
TESTDATA_DIR "/includecollector/project/generated_file.h"};
};
TEST_F(IncludeCollector, IncludesExternalHeader)
{
collector.collect();
ASSERT_THAT(collector.takeIncludeIds(),
AllOf(Contains(id(TESTDATA_DIR "/includecollector/external/external1.h")),
Contains(id(TESTDATA_DIR "/includecollector/external/external2.h")),
Contains(id(TESTDATA_DIR "/includecollector/external/indirect_external.h")),
Contains(id(TESTDATA_DIR "/includecollector/external/indirect_external2.h"))));
}
TEST_F(IncludeCollector, DoesNotIncludesInternalHeader)
{
collector.collect();
ASSERT_THAT(collector.takeIncludeIds(), Not(Contains(id(TESTDATA_DIR "/includecollector/project/header1.h"))));
}
TEST_F(IncludeCollector, NoDuplicate)
{
collector.collect();
ASSERT_THAT(collector.takeIncludeIds(),
UnorderedElementsAre(id(TESTDATA_DIR "/includecollector/external/external1.h"),
id(TESTDATA_DIR "/includecollector/external/external2.h"),
id(TESTDATA_DIR "/includecollector/external/external3.h"),
id(TESTDATA_DIR "/includecollector/external/indirect_external.h"),
id(TESTDATA_DIR "/includecollector/external/indirect_external2.h")));
}
TEST_F(IncludeCollector, IncludesAreSorted)
{
collector.collect();
ASSERT_THAT(collector.takeIncludeIds(),
SizeIs(5));
}
TEST_F(IncludeCollector, If)
{
emptyCollector.addFile(id(TESTDATA_DIR "/includecollector/project/if.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.takeIncludeIds(),
ElementsAre(id(TESTDATA_DIR "/includecollector/project/true.h")));
}
TEST_F(IncludeCollector, LocalPath)
{
emptyCollector.addFile(id(TESTDATA_DIR "/includecollector/project/main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.takeIncludeIds(),
UnorderedElementsAre(id(TESTDATA_DIR "/includecollector/external/external1.h"),
id(TESTDATA_DIR "/includecollector/external/external2.h"),
id(TESTDATA_DIR "/includecollector/external/external3.h"),
id(TESTDATA_DIR "/includecollector/external/indirect_external.h"),
id(TESTDATA_DIR "/includecollector/external/indirect_external2.h")));
}
TEST_F(IncludeCollector, IgnoreMissingFile)
{
emptyCollector.addFile(id(TESTDATA_DIR "/includecollector/project/missingfile.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.takeIncludeIds(),
UnorderedElementsAre(id(TESTDATA_DIR "/includecollector/external/external1.h"),
id(TESTDATA_DIR "/includecollector/external/indirect_external.h"),
id(TESTDATA_DIR "/includecollector/external/indirect_external2.h")));
}
TEST_F(IncludeCollector, IncludesOnlyTopExternalHeader)
{
collector.collect();
ASSERT_THAT(collector.takeTopIncludeIds(),
UnorderedElementsAre(id(TESTDATA_DIR "/includecollector/external/external1.h"),
id(TESTDATA_DIR "/includecollector/external/external2.h"),
id(TESTDATA_DIR "/includecollector/external/external3.h")));
}
TEST_F(IncludeCollector, TopIncludeInIfMacro)
{
emptyCollector.addFile(id(TESTDATA_DIR "/includecollector/project/if.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.setExcludedIncludes({TESTDATA_DIR "/includecollector/project/if.cpp"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.takeTopIncludeIds(),
ElementsAre(id(TESTDATA_DIR "/includecollector/project/true.h")));
}
TEST_F(IncludeCollector, TopIncludeWithLocalPath)
{
emptyCollector.addFile(id(TESTDATA_DIR "/includecollector/project/main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.takeTopIncludeIds(),
UnorderedElementsAre(id(TESTDATA_DIR "/includecollector/external/external1.h"),
id(TESTDATA_DIR "/includecollector/external/external2.h"),
id(TESTDATA_DIR "/includecollector/external/external3.h")));
}
TEST_F(IncludeCollector, TopIncludesIgnoreMissingFile)
{
emptyCollector.addFile(id(TESTDATA_DIR "/includecollector/project/missingfile.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.setExcludedIncludes({TESTDATA_DIR "/includecollector/project/missingfile.cpp"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.takeTopIncludeIds(),
UnorderedElementsAre(id(TESTDATA_DIR "/includecollector/external/external1.h")));
}
TEST_F(IncludeCollector, SourceFiles)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.sourceFiles(),
UnorderedElementsAre(id(TESTDATA_DIR "/symbolscollector_main.cpp"),
id(TESTDATA_DIR "/symbolscollector_header1.h"),
id(TESTDATA_DIR "/symbolscollector_header2.h")));
}
TEST_F(IncludeCollector, MainFileInSourceFiles)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
ASSERT_THAT(emptyCollector.sourceFiles(),
ElementsAre(id(TESTDATA_DIR "/symbolscollector_main.cpp")));
}
TEST_F(IncludeCollector, ResetMainFileInSourceFiles)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
ASSERT_THAT(emptyCollector.sourceFiles(),
ElementsAre(id(TESTDATA_DIR "/symbolscollector_main.cpp")));
}
TEST_F(IncludeCollector, DontDuplicateSourceFiles)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.collect();
emptyCollector.collect();
ASSERT_THAT(emptyCollector.sourceFiles(),
UnorderedElementsAre(id(TESTDATA_DIR "/symbolscollector_main.cpp"),
id(TESTDATA_DIR "/symbolscollector_header1.h"),
id(TESTDATA_DIR "/symbolscollector_header2.h")));
}
TEST_F(IncludeCollector, ClearSourceFiles)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.clear();
ASSERT_THAT(emptyCollector.sourceFiles(), IsEmpty());
}
TEST_F(IncludeCollector, ClearFileStatus)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.collect();
emptyCollector.clear();
ASSERT_THAT(emptyCollector.fileStatuses(), IsEmpty());
}
TEST_F(IncludeCollector, ClearUsedMacros)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_defines.h"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.collect();
emptyCollector.clear();
ASSERT_THAT(emptyCollector.usedMacros(), IsEmpty());
}
TEST_F(IncludeCollector, ClearSourceDependencies)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main2.cpp"), {"cc", "-I" TESTDATA_DIR});
emptyCollector.collect();
emptyCollector.clear();
ASSERT_THAT(emptyCollector.sourceDependencies(), IsEmpty());
}
TEST_F(IncludeCollector, DontCollectSourceFilesAfterFilesAreCleared)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.clear();
emptyCollector.collect();
ASSERT_THAT(emptyCollector.sourceFiles(), IsEmpty());
}
TEST_F(IncludeCollector, DontCollectFileStatusAfterFilesAreCleared)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.clear();
emptyCollector.collect();
ASSERT_THAT(emptyCollector.fileStatuses(), IsEmpty());
}
TEST_F(IncludeCollector, DontCollectUsedMacrosAfterFilesAreCleared)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.clear();
emptyCollector.collect();
ASSERT_THAT(emptyCollector.usedMacros(), IsEmpty());
}
TEST_F(IncludeCollector, DontCollectSourceDependenciesAfterFilesAreCleared)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.clear();
emptyCollector.collect();
ASSERT_THAT(emptyCollector.sourceDependencies(), IsEmpty());
}
TEST_F(IncludeCollector, CollectUsedMacrosWithExternalDefine)
{
auto fileId = id(TESTDATA_DIR "/symbolscollector_defines.h");
emptyCollector.addFile(fileId, {"cc", "-DCOMPILER_ARGUMENT"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.usedMacros(),
ElementsAre(Eq(UsedMacro{"DEFINED", fileId}),
Eq(UsedMacro{"IF_DEFINE", fileId}),
Eq(UsedMacro{"__clang__", fileId}),
Eq(UsedMacro{"CLASS_EXPORT", fileId}),
Eq(UsedMacro{"IF_NOT_DEFINE", fileId}),
Eq(UsedMacro{"MACRO_EXPANSION", fileId}),
Eq(UsedMacro{"COMPILER_ARGUMENT", fileId})));
}
TEST_F(IncludeCollector, CollectUsedMacrosWithoutExternalDefine)
{
auto fileId = id(TESTDATA_DIR "/symbolscollector_defines.h");
emptyCollector.addFile(fileId, {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.usedMacros(),
ElementsAre(Eq(UsedMacro{"DEFINED", fileId}),
Eq(UsedMacro{"IF_DEFINE", fileId}),
Eq(UsedMacro{"__clang__", fileId}),
Eq(UsedMacro{"CLASS_EXPORT", fileId}),
Eq(UsedMacro{"IF_NOT_DEFINE", fileId}),
Eq(UsedMacro{"MACRO_EXPANSION", fileId}),
Eq(UsedMacro{"COMPILER_ARGUMENT", fileId})));
}
TEST_F(IncludeCollector, DontCollectHeaderGuards)
{
auto fileId = id(TESTDATA_DIR "/symbolscollector_defines.h");
emptyCollector.addFile(fileId, {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.usedMacros(),
Not(Contains(Eq(UsedMacro{"SYMBOLSCOLLECTOR_DEFINES_H", fileId}))));
}
TEST_F(IncludeCollector, DISABLED_DontCollectDynamicLibraryExports)
{
auto fileId = id(TESTDATA_DIR "/symbolscollector_defines.h");
emptyCollector.addFile(fileId, {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.usedMacros(),
Not(Contains(Eq(UsedMacro{"CLASS_EXPORT", fileId}))));
}
TEST_F(IncludeCollector, CollectFileStatuses)
{
emptyCollector.addFile(id(TESTDATA_DIR "/symbolscollector_main.cpp"), {"cc", "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system"});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.fileStatuses(),
ElementsAre(
fileStatus(TESTDATA_DIR "/symbolscollector_main.cpp"),
fileStatus(TESTDATA_DIR "/symbolscollector_header1.h"),
fileStatus(TESTDATA_DIR "/symbolscollector_header2.h")));
}
TEST_F(IncludeCollector, CollectSourceDependencies)
{
auto mainFileId = id(TESTDATA_DIR "/symbolscollector_main2.cpp");
auto header1FileId = id(TESTDATA_DIR "/symbolscollector_header1.h");
auto header2FileId = id(TESTDATA_DIR "/symbolscollector_header2.h");
auto header3FileId = id(TESTDATA_DIR "/symbolscollector_header3.h");
emptyCollector.addFile(mainFileId, {"cc", "-I" TESTDATA_DIR});
emptyCollector.collect();
ASSERT_THAT(emptyCollector.sourceDependencies(),
UnorderedElementsAre(SourceDependency(mainFileId, header1FileId),
SourceDependency(mainFileId, header3FileId),
SourceDependency(header3FileId, header2FileId),
SourceDependency(header1FileId, header2FileId)));
}
}

View File

@@ -27,9 +27,9 @@
#include "googletest.h"
#include <builddependenciesgeneratorinterface.h>
#include <builddependencygeneratorinterface.h>
class MockBuildDependenciesGenerator : public ClangBackEnd::BuildDependenciesGeneratorInterface
class MockBuildDependencyGenerator : public ClangBackEnd::BuildDependencyGeneratorInterface
{
public:
MOCK_METHOD1(create,

View File

@@ -43,21 +43,33 @@
namespace {
using ClangBackEnd::FilePath;
using ClangBackEnd::FilePathId;
using ClangBackEnd::FilePathIds;
using ClangBackEnd::FilePathView;
using ClangBackEnd::GeneratedFiles;
using ClangBackEnd::IdPaths;
using ClangBackEnd::ProjectPartPch;
using ClangBackEnd::V2::ProjectPartContainer;
using ClangBackEnd::SourceEntries;
using ClangBackEnd::SourceEntry;
using ClangBackEnd::SourceType;
using ClangBackEnd::V2::FileContainer;
using ClangBackEnd::FilePath;
using ClangBackEnd::FilePathIds;
using ClangBackEnd::FilePathView;
using ClangBackEnd::V2::ProjectPartContainer;
using Utils::PathString;
using Utils::SmallString;
using UnitTests::EndsWith;
MATCHER_P2(HasIdAndType, sourceId, sourceType,
std::string(negation ? "hasn't" : "has") +
PrintToString(ClangBackEnd::SourceEntry(sourceId, sourceType,
-1)))
{
const ClangBackEnd::SourceEntry &entry = arg;
return entry.sourceId == sourceId && entry.sourceType == sourceType;
}
class PchCreator: public ::testing::Test
{
protected:
@@ -74,27 +86,27 @@ protected:
protected:
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database};
FilePath main1Path = TESTDATA_DIR "/includecollector/project/main3.cpp";
FilePath main2Path = TESTDATA_DIR "/includecollector/project/main2.cpp";
FilePath header1Path = TESTDATA_DIR "/includecollector/project/header1.h";
FilePath header2Path = TESTDATA_DIR "/includecollector/project/header2.h";
Utils::SmallStringView generatedFileName = "includecollector/project/generated_file.h";
FilePath generatedFilePath = TESTDATA_DIR "/includecollector/project/generated_file.h";
FilePath main1Path = TESTDATA_DIR "/builddependencycollector/project/main3.cpp";
FilePath main2Path = TESTDATA_DIR "/builddependencycollector/project/main2.cpp";
FilePath header1Path = TESTDATA_DIR "/builddependencycollector/project/header1.h";
FilePath header2Path = TESTDATA_DIR "/builddependencycollector/project/header2.h";
Utils::SmallStringView generatedFileName = "builddependencycollector/project/generated_file.h";
FilePath generatedFilePath = TESTDATA_DIR "/builddependencycollector/project/generated_file.h";
TestEnvironment environment;
FileContainer generatedFile{{TESTDATA_DIR, generatedFileName}, "#pragma once", {}};
NiceMock<MockPchManagerClient> mockPchManagerClient;
NiceMock<MockClangPathWatcher> mockClangPathWatcher;
ClangBackEnd::PchCreator creator{environment, database, mockPchManagerClient, mockClangPathWatcher};
ProjectPartContainer projectPart1{"project1",
{"-I", TESTDATA_DIR, "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system", "-Wno-pragma-once-outside-header"},
{"-I", TESTDATA_DIR, "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system", "-Wno-pragma-once-outside-header"},
{{"DEFINE", "1"}},
{TESTDATA_DIR "/includecollector/external", TESTDATA_DIR "/includecollector/project"},
{TESTDATA_DIR "/builddependencycollector/external", TESTDATA_DIR "/builddependencycollector/project"},
{id(header1Path)},
{id(main1Path)}};
ProjectPartContainer projectPart2{"project2",
{"-I", TESTDATA_DIR, "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-x", "c++-header", "-Wno-pragma-once-outside-header"},
{"-I", TESTDATA_DIR, "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-x", "c++-header", "-Wno-pragma-once-outside-header"},
{{"DEFINE", "1"}},
{TESTDATA_DIR "/includecollector/external", TESTDATA_DIR "/includecollector/project"},
{TESTDATA_DIR "/builddependencycollector/external", TESTDATA_DIR "/builddependencycollector/project"},
{id(header2Path)},
{id(main2Path)}};
};
@@ -112,7 +124,7 @@ TEST_F(PchCreator, CreateProjectPartCommandLine)
{
auto commandLine = creator.generateProjectPartCommandLine(projectPart1);
ASSERT_THAT(commandLine, ElementsAre(environment.clangCompilerPath(), "-I", TESTDATA_DIR, "-I", TESTDATA_DIR "/includecollector/external", "-I", TESTDATA_DIR "/includecollector/project", "-isystem", TESTDATA_DIR "/includecollector/system", "-Wno-pragma-once-outside-header"));
ASSERT_THAT(commandLine, ElementsAre(environment.clangCompilerPath(), "-I", TESTDATA_DIR, "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system", "-Wno-pragma-once-outside-header"));
}
TEST_F(PchCreator, CreateProjectPartHeaders)
@@ -135,37 +147,45 @@ TEST_F(PchCreatorSlowTest, CreateProjectPartPchIncludes)
auto includeIds = creator.generateProjectPartPchIncludes(projectPart1);
ASSERT_THAT(includeIds,
ASSERT_THAT(
includeIds,
AllOf(
Field(&PchCreatorIncludes::includeIds,
AllOf(Contains(id(TESTDATA_DIR "/includecollector/external/external1.h")),
Contains(id(TESTDATA_DIR "/includecollector/external/external2.h")),
Contains(id(TESTDATA_DIR "/includecollector/project/header2.h")),
Contains(id(TESTDATA_DIR "/includecollector/system/system1.h")))),
Field(&PchCreatorIncludes::topSystemIncludeIds,
AllOf(Contains(id(TESTDATA_DIR "/includecollector/system/system1.h")),
Not(Contains(id(TESTDATA_DIR "/includecollector/system/indirect_system.h"))))),
Field(&PchCreatorIncludes::topIncludeIds,
AllOf(Contains(id(TESTDATA_DIR "/includecollector/external/external1.h")),
Contains(id(TESTDATA_DIR "/includecollector/external/external2.h"))))));
Contains(HasIdAndType(
id(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
SourceType::TopInclude)),
Contains(HasIdAndType(
id(TESTDATA_DIR "/builddependencycollector/system/system1.h"),
SourceType::TopSystemInclude)),
Contains(HasIdAndType(
id(TESTDATA_DIR
"/builddependencycollector/system/indirect_system.h"),
SourceType::SystemInclude)),
Contains(HasIdAndType(
id(TESTDATA_DIR
"/builddependencycollector/external/external1.h"),
SourceType::TopInclude)),
Contains(HasIdAndType(
id(TESTDATA_DIR
"/builddependencycollector/external/external2.h"),
SourceType::TopInclude))));
}
TEST_F(PchCreatorSlowTest, CreateProjectPartPchFileContent)
{
auto includes = creator.generateProjectPartPchIncludes(projectPart1);
auto content = creator.generatePchIncludeFileContent(includes.topIncludeIds);
auto content = creator.generatePchIncludeFileContent(creator.topIncludeIds(includes));
ASSERT_THAT(std::string(content),
AllOf(HasSubstr("#include \"" TESTDATA_DIR "/includecollector/project/header2.h\"\n"),
HasSubstr("#include \"" TESTDATA_DIR "/includecollector/external/external1.h\"\n"),
HasSubstr("#include \"" TESTDATA_DIR "/includecollector/external/external2.h\"\n")));
AllOf(HasSubstr("#include \"" TESTDATA_DIR "/builddependencycollector/project/header2.h\"\n"),
HasSubstr("#include \"" TESTDATA_DIR "/builddependencycollector/external/external1.h\"\n"),
HasSubstr("#include \"" TESTDATA_DIR "/builddependencycollector/external/external2.h\"\n")));
}
TEST_F(PchCreatorSlowTest, CreateProjectPartPchIncludeFile)
{
auto includes = creator.generateProjectPartPchIncludes(projectPart1);
auto content = creator.generatePchIncludeFileContent(includes.topIncludeIds);
auto content = creator.generatePchIncludeFileContent(creator.topIncludeIds(includes));
auto pchIncludeFilePath = creator.generateProjectPathPchHeaderFilePath(projectPart1);
auto file = creator.generateFileWithContent(pchIncludeFilePath, content);
file->open(QIODevice::ReadOnly);
@@ -173,9 +193,9 @@ TEST_F(PchCreatorSlowTest, CreateProjectPartPchIncludeFile)
auto fileContent = file->readAll();
ASSERT_THAT(fileContent.toStdString(),
AllOf(HasSubstr("#include \"" TESTDATA_DIR "/includecollector/project/header2.h\"\n"),
HasSubstr("#include \"" TESTDATA_DIR "/includecollector/external/external1.h\"\n"),
HasSubstr("#include \"" TESTDATA_DIR "/includecollector/external/external2.h\"\n")));
AllOf(HasSubstr("#include \"" TESTDATA_DIR "/builddependencycollector/project/header2.h\"\n"),
HasSubstr("#include \"" TESTDATA_DIR "/builddependencycollector/external/external1.h\"\n"),
HasSubstr("#include \"" TESTDATA_DIR "/builddependencycollector/external/external2.h\"\n")));
}
TEST_F(PchCreator, CreateProjectPartPchCompilerArguments)
@@ -235,9 +255,9 @@ TEST_F(PchCreatorVerySlowTest, IdPathsForCreatePchsForProjectParts)
ASSERT_THAT(creator.takeProjectIncludes(),
AllOf(Field(&IdPaths::id, "project1"),
Field(&IdPaths::filePathIds, AllOf(Contains(id(TESTDATA_DIR "/includecollector/project/header2.h")),
Contains(id(TESTDATA_DIR "/includecollector/external/external1.h")),
Contains(id(TESTDATA_DIR "/includecollector/external/external2.h"))))));
Field(&IdPaths::filePathIds, AllOf(Contains(id(TESTDATA_DIR "/builddependencycollector/project/header2.h")),
Contains(id(TESTDATA_DIR "/builddependencycollector/external/external1.h")),
Contains(id(TESTDATA_DIR "/builddependencycollector/external/external2.h"))))));
}
TEST_F(PchCreatorVerySlowTest, ProjectPartPchForCreatesPchForProjectPart)
@@ -276,7 +296,7 @@ TEST_F(PchCreatorVerySlowTest, FaultyProjectPartPchForCreatesNoPchForProjectPart
{{"DEFINE", "1"}},
{"/includes"},
{},
{id(TESTDATA_DIR "/includecollector/project/faulty.cpp")}};
{id(TESTDATA_DIR "/builddependencycollector/project/faulty.cpp")}};
creator.generatePch(faultyProjectPart);
@@ -290,15 +310,14 @@ TEST_F(PchCreator, CreateProjectPartSourcesContent)
{
auto content = creator.generateProjectPartSourcesContent(projectPart1);
ASSERT_THAT(content, Eq("#include \"" TESTDATA_DIR "/includecollector/project/main3.cpp\"\n"));
ASSERT_THAT(content, Eq("#include \"" TESTDATA_DIR "/builddependencycollector/project/main3.cpp\"\n"));
}
TEST_F(PchCreator, Call)
{
auto content = creator.generateProjectPartSourcesContent(projectPart1);
ASSERT_THAT(content, Eq("#include \"" TESTDATA_DIR "/includecollector/project/main3.cpp\"\n"));
ASSERT_THAT(content, Eq("#include \"" TESTDATA_DIR "/builddependencycollector/project/main3.cpp\"\n"));
}
}

View File

@@ -74,10 +74,10 @@ protected:
NiceMock<MockPchManagerClient> mockPchManagerClient;
SmallString projectPartId1 = "project1";
SmallString projectPartId2 = "project2";
PathString main1Path = TESTDATA_DIR "/includecollector_main3.cpp";
PathString main2Path = TESTDATA_DIR "/includecollector_main2.cpp";
PathString header1Path = TESTDATA_DIR "/includecollector_header1.h";
PathString header2Path = TESTDATA_DIR "/includecollector_header2.h";
PathString main1Path = TESTDATA_DIR "/BuildDependencyCollector_main3.cpp";
PathString main2Path = TESTDATA_DIR "/BuildDependencyCollector_main2.cpp";
PathString header1Path = TESTDATA_DIR "/BuildDependencyCollector_header1.h";
PathString header2Path = TESTDATA_DIR "/BuildDependencyCollector_header2.h";
ClangBackEnd::IdPaths idPath{projectPartId1, {1, 2}};
ProjectPartContainer projectPart1{projectPartId1.clone(),
{"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"},

View File

@@ -49,8 +49,8 @@ protected:
{"/yi"},
{{1, 1}},
{{1, 2}}};
SourceEntries firstSources{{1, SourceType::Any, 1}, {2, SourceType::Any, 1}, {10, SourceType::Any, 1}};
BuildDependency buildDependency{firstSources, {}, {}, {}};
SourceEntries firstSources{{1, SourceType::UserInclude, 1}, {2, SourceType::UserInclude, 1}, {10, SourceType::UserInclude, 1}};
BuildDependency buildDependency{firstSources, {}};
};
TEST_F(PchTaskGenerator, Create)

View File

@@ -162,7 +162,7 @@ protected:
ClangBackEnd::FilePathId main2PathId{filePathId(TESTDATA_DIR "/symbolindexer_main2.cpp")};
ClangBackEnd::FilePathId header2PathId{filePathId(TESTDATA_DIR "/symbolindexer_header1.h")};
ClangBackEnd::FilePathId header1PathId{filePathId(TESTDATA_DIR "/symbolindexer_header2.h")};
PathString generatedFileName = "includecollector_generated_file.h";
PathString generatedFileName = "BuildDependencyCollector_generated_file.h";
ClangBackEnd::FilePathId generatedFilePathId21;
ProjectPartContainer projectPart1{"project1",
{"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"},

View File

@@ -106,7 +106,8 @@ SOURCES += \
pchtaskgenerator-test.cpp \
compilationdatabaseutils-test.cpp \
builddependenciesprovider-test.cpp \
builddependenciesstorage-test.cpp
builddependenciesstorage-test.cpp \
builddependencycollector-test.cpp
!isEmpty(LIBCLANG_LIBS) {
SOURCES += \
@@ -172,7 +173,6 @@ SOURCES += \
clangqueryprojectfindfilter-test.cpp \
clangquery-test.cpp \
gtest-clang-printing.cpp \
includecollector-test.cpp \
pchcreator-test.cpp \
refactoringclientserverinprocess-test.cpp \
refactoringclient-test.cpp \
@@ -252,8 +252,8 @@ HEADERS += \
mocktaskscheduler.h \
mockbuilddependenciesprovider.h \
mockmodifiedtimechecker.h \
mockbuilddependenciesgenerator.h \
mockbuilddependenciesstorage.h
mockbuilddependenciesstorage.h \
mockbuilddependencygenerator.h
!isEmpty(LIBCLANG_LIBS) {
HEADERS += \