forked from qt-creator/qt-creator
Clang: Add timer based path notification compression
QFileWatcher is only reporting one path per signal which is suboptimal if you change many files at once. This patch is introducing a timer which is waiting some time time to see if more path changes are reported and is collecting them in a vector. Change-Id: I50f7c21186353b199634e7b3cd5a41f8d581a31d Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
@@ -37,6 +37,7 @@
|
|||||||
#include <QFileSystemWatcher>
|
#include <QFileSystemWatcher>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QTemporaryDir>
|
#include <QTemporaryDir>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
using ClangBackEnd::ClangPathWatcher;
|
using ClangBackEnd::ClangPathWatcher;
|
||||||
using ClangBackEnd::ConnectionServer;
|
using ClangBackEnd::ConnectionServer;
|
||||||
@@ -93,11 +94,15 @@ int main(int argc, char *argv[])
|
|||||||
const QString connection = processArguments(application);
|
const QString connection = processArguments(application);
|
||||||
|
|
||||||
StringCache<Utils::SmallString> filePathCache;
|
StringCache<Utils::SmallString> filePathCache;
|
||||||
ClangPathWatcher<QFileSystemWatcher> includeWatcher(filePathCache);
|
ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher(filePathCache);
|
||||||
ApplicationEnvironment environment;
|
ApplicationEnvironment environment;
|
||||||
PchCreator pchCreator(environment, filePathCache);
|
PchCreator pchCreator(environment, filePathCache);
|
||||||
ProjectParts projectParts;
|
ProjectParts projectParts;
|
||||||
PchManagerServer clangPchManagerServer(filePathCache, includeWatcher, pchCreator, projectParts);
|
PchManagerServer clangPchManagerServer(filePathCache,
|
||||||
|
includeWatcher,
|
||||||
|
pchCreator,
|
||||||
|
projectParts);
|
||||||
|
includeWatcher.setNotifier(&clangPchManagerServer);
|
||||||
ConnectionServer<PchManagerServer, PchManagerClientProxy> connectionServer(connection);
|
ConnectionServer<PchManagerServer, PchManagerClientProxy> connectionServer(connection);
|
||||||
connectionServer.start();
|
connectionServer.start();
|
||||||
connectionServer.setServer(&clangPchManagerServer);
|
connectionServer.setServer(&clangPchManagerServer);
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <clangpchmanagerbackend_global.h>
|
||||||
|
|
||||||
|
#include <utils/smallstringvector.h>
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
|
template <typename Timer>
|
||||||
|
class ChangedFilePathCompressor non_unittest_final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ChangedFilePathCompressor()
|
||||||
|
{
|
||||||
|
m_timer.setSingleShot(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~ChangedFilePathCompressor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void addFilePath(const QString &filePath)
|
||||||
|
{
|
||||||
|
m_filePaths.push_back(filePath);
|
||||||
|
|
||||||
|
restartTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::SmallStringVector takeFilePaths()
|
||||||
|
{
|
||||||
|
return std::move(m_filePaths);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void setCallback(std::function<void(Utils::SmallStringVector &&)> &&callback)
|
||||||
|
{
|
||||||
|
QObject::connect(&m_timer,
|
||||||
|
&Timer::timeout,
|
||||||
|
[this, callback=std::move(callback)] { callback(takeFilePaths()); });
|
||||||
|
}
|
||||||
|
|
||||||
|
unitttest_public:
|
||||||
|
virtual void restartTimer()
|
||||||
|
{
|
||||||
|
m_timer.start(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer &timer()
|
||||||
|
{
|
||||||
|
return m_timer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Utils::SmallStringVector m_filePaths;
|
||||||
|
Timer m_timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ClangBackEnd
|
||||||
@@ -27,9 +27,10 @@
|
|||||||
|
|
||||||
#include "clangpathwatcherinterface.h"
|
#include "clangpathwatcherinterface.h"
|
||||||
#include "clangpathwatchernotifier.h"
|
#include "clangpathwatchernotifier.h"
|
||||||
|
#include "changedfilepathcompressor.h"
|
||||||
#include "stringcache.h"
|
#include "stringcache.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QTimer>
|
||||||
|
|
||||||
namespace ClangBackEnd {
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
@@ -60,7 +61,10 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename FileSystemWatcher>
|
using WatcherEntries = std::vector<WatcherEntry>;
|
||||||
|
|
||||||
|
template <typename FileSystemWatcher,
|
||||||
|
typename Timer>
|
||||||
class ClangPathWatcher : public ClangPathWatcherInterface
|
class ClangPathWatcher : public ClangPathWatcherInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -71,7 +75,16 @@ public:
|
|||||||
{
|
{
|
||||||
QObject::connect(&m_fileSystemWatcher,
|
QObject::connect(&m_fileSystemWatcher,
|
||||||
&FileSystemWatcher::fileChanged,
|
&FileSystemWatcher::fileChanged,
|
||||||
[&] (const QString &filePath) { addChangedPathForFilePath(filePath); });
|
[&] (const QString &filePath) { compressChangedFilePath(filePath); });
|
||||||
|
|
||||||
|
m_changedFilePathCompressor.setCallback([&] (Utils::SmallStringVector &&filePaths) {
|
||||||
|
addChangedPathForFilePath(std::move(filePaths));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
~ClangPathWatcher()
|
||||||
|
{
|
||||||
|
m_changedFilePathCompressor.setCallback([&] (Utils::SmallStringVector &&) {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateIdPaths(const std::vector<IdPaths> &idPaths) override
|
void updateIdPaths(const std::vector<IdPaths> &idPaths) override
|
||||||
@@ -136,10 +149,10 @@ unitttest_public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::pair<std::vector<WatcherEntry>,std::vector<uint>>
|
std::pair<WatcherEntries,std::vector<uint>>
|
||||||
convertIdPathsToWatcherEntriesAndIds(const std::vector<IdPaths> &idPaths)
|
convertIdPathsToWatcherEntriesAndIds(const std::vector<IdPaths> &idPaths)
|
||||||
{
|
{
|
||||||
std::vector<WatcherEntry> entries;
|
WatcherEntries entries;
|
||||||
entries.reserve(sizeOfIdPaths(idPaths));
|
entries.reserve(sizeOfIdPaths(idPaths));
|
||||||
std::vector<uint> ids;
|
std::vector<uint> ids;
|
||||||
ids.reserve(ids.size());
|
ids.reserve(ids.size());
|
||||||
@@ -164,7 +177,7 @@ unitttest_public:
|
|||||||
return {entries, ids};
|
return {entries, ids};
|
||||||
}
|
}
|
||||||
|
|
||||||
void addEntries(const std::vector<WatcherEntry> &entries)
|
void addEntries(const WatcherEntries &entries)
|
||||||
{
|
{
|
||||||
auto newEntries = notWatchedEntries(entries);
|
auto newEntries = notWatchedEntries(entries);
|
||||||
|
|
||||||
@@ -176,7 +189,7 @@ unitttest_public:
|
|||||||
m_fileSystemWatcher.addPaths(convertWatcherEntriesToQStringList(filteredPaths));
|
m_fileSystemWatcher.addPaths(convertWatcherEntriesToQStringList(filteredPaths));
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeUnusedEntries(const std::vector<WatcherEntry> &entries,
|
void removeUnusedEntries(const WatcherEntries &entries,
|
||||||
const std::vector<uint> &ids)
|
const std::vector<uint> &ids)
|
||||||
{
|
{
|
||||||
auto oldEntries = notAnymoreWatchedEntriesWithIds(entries, ids);
|
auto oldEntries = notAnymoreWatchedEntriesWithIds(entries, ids);
|
||||||
@@ -195,7 +208,7 @@ unitttest_public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
QStringList convertWatcherEntriesToQStringList(
|
QStringList convertWatcherEntriesToQStringList(
|
||||||
const std::vector<WatcherEntry> &watcherEntries)
|
const WatcherEntries &watcherEntries)
|
||||||
{
|
{
|
||||||
QStringList paths;
|
QStringList paths;
|
||||||
paths.reserve(int(watcherEntries.size()));
|
paths.reserve(int(watcherEntries.size()));
|
||||||
@@ -209,10 +222,10 @@ unitttest_public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Compare>
|
template <typename Compare>
|
||||||
std::vector<WatcherEntry> notWatchedEntries(const std::vector<WatcherEntry> &entries,
|
WatcherEntries notWatchedEntries(const WatcherEntries &entries,
|
||||||
Compare compare) const
|
Compare compare) const
|
||||||
{
|
{
|
||||||
std::vector<WatcherEntry> notWatchedEntries;
|
WatcherEntries notWatchedEntries;
|
||||||
notWatchedEntries.reserve(entries.size());
|
notWatchedEntries.reserve(entries.size());
|
||||||
|
|
||||||
std::set_difference(entries.begin(),
|
std::set_difference(entries.begin(),
|
||||||
@@ -225,12 +238,12 @@ unitttest_public:
|
|||||||
return notWatchedEntries;
|
return notWatchedEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<WatcherEntry> notWatchedEntries(const std::vector<WatcherEntry> &entries) const
|
WatcherEntries notWatchedEntries(const WatcherEntries &entries) const
|
||||||
{
|
{
|
||||||
return notWatchedEntries(entries, std::less<WatcherEntry>());
|
return notWatchedEntries(entries, std::less<WatcherEntry>());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<WatcherEntry> notWatchedPaths(const std::vector<WatcherEntry> &entries) const
|
WatcherEntries notWatchedPaths(const WatcherEntries &entries) const
|
||||||
{
|
{
|
||||||
auto compare = [] (const WatcherEntry &first, const WatcherEntry &second) {
|
auto compare = [] (const WatcherEntry &first, const WatcherEntry &second) {
|
||||||
return first.path < second.path;
|
return first.path < second.path;
|
||||||
@@ -240,11 +253,11 @@ unitttest_public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Compare>
|
template <typename Compare>
|
||||||
std::vector<WatcherEntry> notAnymoreWatchedEntries(
|
WatcherEntries notAnymoreWatchedEntries(
|
||||||
const std::vector<WatcherEntry> &newEntries,
|
const WatcherEntries &newEntries,
|
||||||
Compare compare) const
|
Compare compare) const
|
||||||
{
|
{
|
||||||
std::vector<WatcherEntry> notAnymoreWatchedEntries;
|
WatcherEntries notAnymoreWatchedEntries;
|
||||||
notAnymoreWatchedEntries.reserve(m_watchedEntries.size());
|
notAnymoreWatchedEntries.reserve(m_watchedEntries.size());
|
||||||
|
|
||||||
std::set_difference(m_watchedEntries.cbegin(),
|
std::set_difference(m_watchedEntries.cbegin(),
|
||||||
@@ -257,8 +270,8 @@ unitttest_public:
|
|||||||
return notAnymoreWatchedEntries;
|
return notAnymoreWatchedEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<WatcherEntry> notAnymoreWatchedEntriesWithIds(
|
WatcherEntries notAnymoreWatchedEntriesWithIds(
|
||||||
const std::vector<WatcherEntry> &newEntries,
|
const WatcherEntries &newEntries,
|
||||||
const std::vector<uint> &ids) const
|
const std::vector<uint> &ids) const
|
||||||
{
|
{
|
||||||
auto oldEntries = notAnymoreWatchedEntries(newEntries, std::less<WatcherEntry>());
|
auto oldEntries = notAnymoreWatchedEntries(newEntries, std::less<WatcherEntry>());
|
||||||
@@ -274,9 +287,9 @@ unitttest_public:
|
|||||||
return oldEntries;
|
return oldEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mergeToWatchedEntries(const std::vector<WatcherEntry> &newEntries)
|
void mergeToWatchedEntries(const WatcherEntries &newEntries)
|
||||||
{
|
{
|
||||||
std::vector<WatcherEntry> newWatchedEntries;
|
WatcherEntries newWatchedEntries;
|
||||||
newWatchedEntries.reserve(m_watchedEntries.size() + newEntries.size());
|
newWatchedEntries.reserve(m_watchedEntries.size() + newEntries.size());
|
||||||
|
|
||||||
std::merge(m_watchedEntries.cbegin(),
|
std::merge(m_watchedEntries.cbegin(),
|
||||||
@@ -289,9 +302,9 @@ unitttest_public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
std::vector<WatcherEntry> uniquePaths(const std::vector<WatcherEntry> &pathEntries)
|
WatcherEntries uniquePaths(const WatcherEntries &pathEntries)
|
||||||
{
|
{
|
||||||
std::vector<WatcherEntry> uniqueEntries;
|
WatcherEntries uniqueEntries;
|
||||||
|
|
||||||
auto compare = [] (const WatcherEntry &first, const WatcherEntry &second) {
|
auto compare = [] (const WatcherEntry &first, const WatcherEntry &second) {
|
||||||
return first.path == second.path;
|
return first.path == second.path;
|
||||||
@@ -305,17 +318,17 @@ unitttest_public:
|
|||||||
return uniqueEntries;
|
return uniqueEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<WatcherEntry> filterNotWatchedPaths(const std::vector<WatcherEntry> &entries)
|
WatcherEntries filterNotWatchedPaths(const WatcherEntries &entries)
|
||||||
{
|
{
|
||||||
return notWatchedPaths(uniquePaths(entries));
|
return notWatchedPaths(uniquePaths(entries));
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<WatcherEntry> &watchedEntries() const
|
const WatcherEntries &watchedEntries() const
|
||||||
{
|
{
|
||||||
return m_watchedEntries;
|
return m_watchedEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<WatcherEntry> removeIdsFromWatchedEntries(const std::vector<uint> &ids)
|
WatcherEntries removeIdsFromWatchedEntries(const std::vector<uint> &ids)
|
||||||
{
|
{
|
||||||
|
|
||||||
auto keep = [&] (const WatcherEntry &entry) {
|
auto keep = [&] (const WatcherEntry &entry) {
|
||||||
@@ -326,16 +339,16 @@ unitttest_public:
|
|||||||
m_watchedEntries.end(),
|
m_watchedEntries.end(),
|
||||||
keep);
|
keep);
|
||||||
|
|
||||||
std::vector<WatcherEntry> removedEntries(found, m_watchedEntries.end());
|
WatcherEntries removedEntries(found, m_watchedEntries.end());
|
||||||
|
|
||||||
m_watchedEntries.erase(found, m_watchedEntries.end());
|
m_watchedEntries.erase(found, m_watchedEntries.end());
|
||||||
|
|
||||||
return removedEntries;
|
return removedEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeFromWatchedEntries(const std::vector<WatcherEntry> &oldEntries)
|
void removeFromWatchedEntries(const WatcherEntries &oldEntries)
|
||||||
{
|
{
|
||||||
std::vector<WatcherEntry> newWatchedEntries;
|
WatcherEntries newWatchedEntries;
|
||||||
newWatchedEntries.reserve(m_watchedEntries.size() - oldEntries.size());
|
newWatchedEntries.reserve(m_watchedEntries.size() - oldEntries.size());
|
||||||
|
|
||||||
std::set_difference(m_watchedEntries.cbegin(),
|
std::set_difference(m_watchedEntries.cbegin(),
|
||||||
@@ -348,25 +361,57 @@ unitttest_public:
|
|||||||
m_watchedEntries = newWatchedEntries;
|
m_watchedEntries = newWatchedEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addChangedPathForFilePath(const QString &filePath)
|
void compressChangedFilePath(const QString &filePath)
|
||||||
{
|
{
|
||||||
uint pathId = m_pathCache.stringId(Utils::SmallString(filePath));
|
m_changedFilePathCompressor.addFilePath(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
auto range = std::equal_range(m_watchedEntries.begin(), m_watchedEntries.end(), pathId);
|
WatcherEntries watchedEntriesForPaths(Utils::SmallStringVector &&filePaths)
|
||||||
|
{
|
||||||
|
std::vector<uint> pathIds = m_pathCache.stringIds(filePaths);
|
||||||
|
|
||||||
Utils::SmallStringVector changedIds;
|
WatcherEntries foundEntries;
|
||||||
|
|
||||||
std::transform(range.first,
|
for (uint pathId : pathIds) {
|
||||||
range.second,
|
auto range = std::equal_range(m_watchedEntries.begin(), m_watchedEntries.end(), pathId);
|
||||||
std::back_inserter(changedIds),
|
foundEntries.insert(foundEntries.end(), range.first, range.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::SmallStringVector idsForWatcherEntries(const WatcherEntries &foundEntries)
|
||||||
|
{
|
||||||
|
Utils::SmallStringVector ids;
|
||||||
|
|
||||||
|
std::transform(foundEntries.begin(),
|
||||||
|
foundEntries.end(),
|
||||||
|
std::back_inserter(ids),
|
||||||
[&] (const WatcherEntry &entry) {
|
[&] (const WatcherEntry &entry) {
|
||||||
return m_idCache.string(entry.id);
|
return m_idCache.string(entry.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
std::sort(changedIds.begin(), changedIds.end());
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_notifier)
|
Utils::SmallStringVector uniqueIds(Utils::SmallStringVector &&ids)
|
||||||
m_notifier->pathsWithIdsChanged(changedIds);
|
{
|
||||||
|
std::sort(ids.begin(), ids.end());
|
||||||
|
auto newEnd = std::unique(ids.begin(), ids.end());
|
||||||
|
ids.erase(newEnd, ids.end());
|
||||||
|
|
||||||
|
return std::move(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addChangedPathForFilePath(Utils::SmallStringVector &&filePaths)
|
||||||
|
{
|
||||||
|
if (m_notifier) {
|
||||||
|
WatcherEntries foundEntries = watchedEntriesForPaths(std::move(filePaths));
|
||||||
|
|
||||||
|
Utils::SmallStringVector changedIds = idsForWatcherEntries(foundEntries);
|
||||||
|
|
||||||
|
m_notifier->pathsWithIdsChanged(uniqueIds(std::move(changedIds)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StringCache<Utils::SmallString> &pathCache()
|
StringCache<Utils::SmallString> &pathCache()
|
||||||
@@ -381,7 +426,8 @@ unitttest_public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
StringCache<Utils::SmallString> m_idCache;
|
StringCache<Utils::SmallString> m_idCache;
|
||||||
std::vector<WatcherEntry> m_watchedEntries;
|
WatcherEntries m_watchedEntries;
|
||||||
|
ChangedFilePathCompressor<Timer> m_changedFilePathCompressor;
|
||||||
FileSystemWatcher m_fileSystemWatcher;
|
FileSystemWatcher m_fileSystemWatcher;
|
||||||
StringCache<Utils::SmallString> &m_pathCache;
|
StringCache<Utils::SmallString> &m_pathCache;
|
||||||
ClangPathWatcherNotifier *m_notifier;
|
ClangPathWatcherNotifier *m_notifier;
|
||||||
|
|||||||
@@ -29,4 +29,5 @@ HEADERS += \
|
|||||||
$$PWD/pchcreatorinterface.h \
|
$$PWD/pchcreatorinterface.h \
|
||||||
$$PWD/clangpathwatcherinterface.h \
|
$$PWD/clangpathwatcherinterface.h \
|
||||||
$$PWD/projectpartsinterface.h \
|
$$PWD/projectpartsinterface.h \
|
||||||
$$PWD/clangpathwatchernotifier.h
|
$$PWD/clangpathwatchernotifier.h \
|
||||||
|
$$PWD/changedfilepathcompressor.h
|
||||||
|
|||||||
@@ -27,8 +27,10 @@
|
|||||||
|
|
||||||
#ifdef UNIT_TESTS
|
#ifdef UNIT_TESTS
|
||||||
#define unitttest_public public
|
#define unitttest_public public
|
||||||
|
#define non_unittest_final
|
||||||
#else
|
#else
|
||||||
#define unitttest_public private
|
#define unitttest_public private
|
||||||
|
#define non_unittest_final final
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|||||||
@@ -65,14 +65,12 @@ std::vector<uint> IncludeCollector::generateExcludedIncludeFileUIDs(clang::FileM
|
|||||||
std::vector<uint> fileUIDs;
|
std::vector<uint> fileUIDs;
|
||||||
fileUIDs.reserve(m_excludedIncludes.size());
|
fileUIDs.reserve(m_excludedIncludes.size());
|
||||||
|
|
||||||
auto generateUID = [&] (const Utils::SmallString &filePath) {
|
for (const Utils::SmallString &filePath : m_excludedIncludes) {
|
||||||
return fileManager.getFile({filePath.data(), filePath.size()})->getUID();
|
const clang::FileEntry *file = fileManager.getFile({filePath.data(), filePath.size()});
|
||||||
};
|
|
||||||
|
|
||||||
std::transform(m_excludedIncludes.begin(),
|
if (file)
|
||||||
m_excludedIncludes.end(),
|
fileUIDs.push_back(file->getUID());
|
||||||
std::back_inserter(fileUIDs),
|
}
|
||||||
generateUID);
|
|
||||||
|
|
||||||
std::sort(fileUIDs.begin(), fileUIDs.end());
|
std::sort(fileUIDs.begin(), fileUIDs.end());
|
||||||
|
|
||||||
|
|||||||
87
tests/unit/unittest/changedfilepathcompressor-test.cpp
Normal file
87
tests/unit/unittest/changedfilepathcompressor-test.cpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 <mockchangedfilepathcompressor.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using testing::ElementsAre;
|
||||||
|
using testing::Invoke;
|
||||||
|
using testing::IsEmpty;
|
||||||
|
using testing::NiceMock;
|
||||||
|
|
||||||
|
class ChangedFilePathCompressor : public testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void SetUp();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
NiceMock<MockChangedFilePathCompressor> mockCompressor;
|
||||||
|
ClangBackEnd::ChangedFilePathCompressor<FakeTimer> compressor;
|
||||||
|
QString filePath1{"filePath1"};
|
||||||
|
QString filePath2{"filePath2"};
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(ChangedFilePathCompressor, AddFilePath)
|
||||||
|
{
|
||||||
|
mockCompressor.addFilePath(filePath1);
|
||||||
|
|
||||||
|
ASSERT_THAT(mockCompressor.takeFilePaths(), ElementsAre(filePath1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ChangedFilePathCompressor, NoFilePathsAferTakenThem)
|
||||||
|
{
|
||||||
|
mockCompressor.addFilePath(filePath1);
|
||||||
|
|
||||||
|
mockCompressor.takeFilePaths();
|
||||||
|
|
||||||
|
ASSERT_THAT(mockCompressor.takeFilePaths(), IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ChangedFilePathCompressor, CallRestartTimerAfterAddingPath)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(mockCompressor, restartTimer());
|
||||||
|
|
||||||
|
mockCompressor.addFilePath(filePath1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ChangedFilePathCompressor, CallTimeOutAfterAddingPath)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(mockCompressor, callbackCalled(ElementsAre(filePath1, filePath2)));
|
||||||
|
|
||||||
|
compressor.addFilePath(filePath1);
|
||||||
|
compressor.addFilePath(filePath2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChangedFilePathCompressor::SetUp()
|
||||||
|
{
|
||||||
|
compressor.setCallback([&] (Utils::SmallStringVector &&filePaths) {
|
||||||
|
mockCompressor.callbackCalled(filePaths);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "googletest.h"
|
#include "googletest.h"
|
||||||
|
|
||||||
|
#include "faketimer.h"
|
||||||
#include "mockqfilesystemwatcher.h"
|
#include "mockqfilesystemwatcher.h"
|
||||||
#include "mockclangpathwatchernotifier.h"
|
#include "mockclangpathwatchernotifier.h"
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ using testing::IsEmpty;
|
|||||||
using testing::SizeIs;
|
using testing::SizeIs;
|
||||||
using testing::NiceMock;
|
using testing::NiceMock;
|
||||||
|
|
||||||
using Watcher = ClangBackEnd::ClangPathWatcher<NiceMock<MockQFileSytemWatcher>>;
|
using Watcher = ClangBackEnd::ClangPathWatcher<NiceMock<MockQFileSytemWatcher>, FakeTimer>;
|
||||||
using ClangBackEnd::WatcherEntry;
|
using ClangBackEnd::WatcherEntry;
|
||||||
|
|
||||||
class ClangPathWatcher : public testing::Test
|
class ClangPathWatcher : public testing::Test
|
||||||
@@ -310,4 +311,14 @@ TEST_F(ClangPathWatcher, NotifyFileChange)
|
|||||||
mockQFileSytemWatcher.fileChanged(path1.toQString());
|
mockQFileSytemWatcher.fileChanged(path1.toQString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ClangPathWatcher, TwoNotifyFileChanges)
|
||||||
|
{
|
||||||
|
watcher.addEntries({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4, watcherEntry5});
|
||||||
|
|
||||||
|
EXPECT_CALL(notifier, pathsWithIdsChanged(ElementsAre(id2, id3, id1)));
|
||||||
|
|
||||||
|
mockQFileSytemWatcher.fileChanged(path2.toQString());
|
||||||
|
mockQFileSytemWatcher.fileChanged(path1.toQString());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
46
tests/unit/unittest/faketimer.cpp
Normal file
46
tests/unit/unittest/faketimer.cpp
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "faketimer.h"
|
||||||
|
|
||||||
|
FakeTimer::~FakeTimer()
|
||||||
|
{
|
||||||
|
emitTimoutIfStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FakeTimer::start(int)
|
||||||
|
{
|
||||||
|
m_isStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FakeTimer::setSingleShot(bool)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FakeTimer::emitTimoutIfStarted()
|
||||||
|
{
|
||||||
|
if (m_isStarted)
|
||||||
|
emit timeout();
|
||||||
|
}
|
||||||
46
tests/unit/unittest/faketimer.h
Normal file
46
tests/unit/unittest/faketimer.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class FakeTimer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
~FakeTimer();
|
||||||
|
|
||||||
|
void start(int interval);
|
||||||
|
void setSingleShot(bool);
|
||||||
|
|
||||||
|
void emitTimoutIfStarted();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void timeout();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isStarted = false;
|
||||||
|
};
|
||||||
43
tests/unit/unittest/mockchangedfilepathcompressor.h
Normal file
43
tests/unit/unittest/mockchangedfilepathcompressor.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "googletest.h"
|
||||||
|
|
||||||
|
#include "faketimer.h"
|
||||||
|
|
||||||
|
#include <changedfilepathcompressor.h>
|
||||||
|
|
||||||
|
class MockChangedFilePathCompressor : public ClangBackEnd::ChangedFilePathCompressor<FakeTimer>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD0(restartTimer,
|
||||||
|
void ());
|
||||||
|
|
||||||
|
MOCK_METHOD1(callbackCalled,
|
||||||
|
void (const Utils::SmallStringVector &filePaths));
|
||||||
|
};
|
||||||
|
|
||||||
@@ -47,7 +47,9 @@ SOURCES += \
|
|||||||
clientserveroutsideprocess-test.cpp \
|
clientserveroutsideprocess-test.cpp \
|
||||||
clangpathwatcher-test.cpp \
|
clangpathwatcher-test.cpp \
|
||||||
projectparts-test.cpp \
|
projectparts-test.cpp \
|
||||||
stringcache-test.cpp
|
stringcache-test.cpp \
|
||||||
|
changedfilepathcompressor-test.cpp \
|
||||||
|
faketimer.cpp
|
||||||
|
|
||||||
!isEmpty(LIBCLANG_LIBS) {
|
!isEmpty(LIBCLANG_LIBS) {
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
@@ -144,7 +146,9 @@ HEADERS += \
|
|||||||
mockqfilesystemwatcher.h \
|
mockqfilesystemwatcher.h \
|
||||||
mockclangpathwatcher.h \
|
mockclangpathwatcher.h \
|
||||||
mockprojectparts.h \
|
mockprojectparts.h \
|
||||||
mockclangpathwatchernotifier.h
|
mockclangpathwatchernotifier.h \
|
||||||
|
mockchangedfilepathcompressor.h \
|
||||||
|
faketimer.h
|
||||||
|
|
||||||
!isEmpty(LIBCLANG_LIBS) {
|
!isEmpty(LIBCLANG_LIBS) {
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
|||||||
Reference in New Issue
Block a user