aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@qt.io>2019-06-28 12:50:03 +0200
committerEike Ziller <eike.ziller@qt.io>2019-06-28 12:50:03 +0200
commit10098b2508abe6e8df59b7e27ea64e9483f1f8be (patch)
treeb73815f1e8ca7aa12c347706b410050e3eb22caa /src/libs
parent5dbfd46bcfe177b8308c70a66f7d404429249f6b (diff)
parenta111f251261159b50e92d6866f2058c66b43e390 (diff)
Merge remote-tracking branch 'origin/4.10'
Conflicts: CMakeLists.txt tests/unit/unittest/unittest.pro Change-Id: I64296ad31502d9b35012da129a28e9277e9fcf8e
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/clangsupport/clangpathwatcher.h214
-rw-r--r--src/libs/clangsupport/clangsupport-lib.pri11
-rw-r--r--src/libs/clangsupport/directoryandfilepathid.h90
-rw-r--r--src/libs/clangsupport/directorypathcompressor.h (renamed from src/libs/clangsupport/changedfilepathcompressor.h)48
-rw-r--r--src/libs/clangsupport/directorypathid.h81
-rw-r--r--src/libs/clangsupport/filepathcache.h48
-rw-r--r--src/libs/clangsupport/filepathcaching.cpp15
-rw-r--r--src/libs/clangsupport/filepathcaching.h3
-rw-r--r--src/libs/clangsupport/filepathcachinginterface.h6
-rw-r--r--src/libs/clangsupport/filepathexceptions.h9
-rw-r--r--src/libs/clangsupport/filepathstorage.h22
-rw-r--r--src/libs/clangsupport/filepathstoragesqlitestatementfactory.h2
-rw-r--r--src/libs/clangsupport/filestatus.h63
-rw-r--r--src/libs/clangsupport/filestatuscache.cpp137
-rw-r--r--src/libs/clangsupport/filestatuscache.h96
-rw-r--r--src/libs/clangsupport/filesystem.cpp61
-rw-r--r--src/libs/clangsupport/filesystem.h48
-rw-r--r--src/libs/clangsupport/filesysteminterface.h43
-rw-r--r--src/libs/clangsupport/modifiedtimechecker.h184
-rw-r--r--src/libs/clangsupport/modifiedtimecheckerinterface.h1
-rw-r--r--src/libs/clangsupport/refactoringdatabaseinitializer.h4
-rw-r--r--src/libs/clangsupport/set_algorithm.h101
-rw-r--r--src/libs/clangsupport/sourceentry.h4
-rw-r--r--src/libs/languageserverprotocol/icontent.h5
-rw-r--r--src/libs/qmljs/qmljscheck.cpp2
-rw-r--r--src/libs/utils/smallstringview.h4
26 files changed, 1045 insertions, 257 deletions
diff --git a/src/libs/clangsupport/clangpathwatcher.h b/src/libs/clangsupport/clangpathwatcher.h
index dab52996c2..7a7d6ccfcf 100644
--- a/src/libs/clangsupport/clangpathwatcher.h
+++ b/src/libs/clangsupport/clangpathwatcher.h
@@ -1,4 +1,4 @@
-/****************************************************************************
+; /****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
@@ -27,71 +27,94 @@
#include "clangpathwatcherinterface.h"
#include "clangpathwatchernotifier.h"
-#include "changedfilepathcompressor.h"
+#include "directorypathcompressor.h"
#include "filepathcachinginterface.h"
+#include "filesystem.h"
#include "stringcache.h"
+#include <utils/algorithm.h>
+
#include <QTimer>
namespace ClangBackEnd {
+template<class InputIt1, class InputIt2, class Callable>
+void set_greedy_intersection_call(
+ InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable callable)
+{
+ while (first1 != last1 && first2 != last2) {
+ if (*first1 < *first2) {
+ ++first1;
+ } else {
+ if (*first2 < *first1)
+ ++first2;
+ else
+ callable(*first1++);
+ }
+ }
+}
+
class WatcherEntry
{
public:
ProjectPartId id;
- FilePathId pathId;
+ DirectoryPathId directoryPathId;
+ FilePathId filePathId;
+ long long lastModified = -1;
friend bool operator==(WatcherEntry first, WatcherEntry second)
{
- return first.id == second.id && first.pathId == second.pathId;
+ return first.id == second.id && first.directoryPathId == second.directoryPathId
+ && first.filePathId == second.filePathId;
}
friend bool operator<(WatcherEntry first, WatcherEntry second)
{
- return std::tie(first.pathId, first.id) < std::tie(second.pathId, second.id);
+ return std::tie(first.directoryPathId, first.filePathId, first.id)
+ < std::tie(second.directoryPathId, second.filePathId, second.id);
}
- friend bool operator<(WatcherEntry entry, FilePathId pathId)
+ friend bool operator<(DirectoryPathId directoryPathId, WatcherEntry entry)
{
- return entry.pathId < pathId;
+ return directoryPathId < entry.directoryPathId;
}
- friend bool operator<(FilePathId pathId, WatcherEntry entry)
+ friend bool operator<(WatcherEntry entry, DirectoryPathId directoryPathId)
{
- return pathId < entry.pathId;
+ return entry.directoryPathId < directoryPathId;
}
- operator FilePathId() const
- {
- return pathId;
- }
+ operator FilePathId() const { return filePathId; }
+
+ operator DirectoryPathId() const { return directoryPathId; }
};
using WatcherEntries = std::vector<WatcherEntry>;
-template <typename FileSystemWatcher,
- typename Timer>
+template<typename FileSystemWatcher, typename Timer>
class CLANGSUPPORT_GCCEXPORT ClangPathWatcher : public ClangPathWatcherInterface
{
public:
ClangPathWatcher(FilePathCachingInterface &pathCache,
- ClangPathWatcherNotifier *notifier=nullptr)
- : m_changedFilePathCompressor(pathCache),
- m_pathCache(pathCache),
- m_notifier(notifier)
+ FileSystemInterface &fileSystem,
+ ClangPathWatcherNotifier *notifier = nullptr)
+ : m_pathCache(pathCache)
+ , m_fileStatusCache(fileSystem)
+ , m_fileSystem(fileSystem)
+ , m_notifier(notifier)
{
QObject::connect(&m_fileSystemWatcher,
- &FileSystemWatcher::fileChanged,
- [&] (const QString &filePath) { compressChangedFilePath(filePath); });
+ &FileSystemWatcher::directoryChanged,
+ [&](const QString &path) { compressChangedDirectoryPath(path); });
- m_changedFilePathCompressor.setCallback([&] (ClangBackEnd::FilePathIds &&filePathIds) {
- addChangedPathForFilePath(std::move(filePathIds));
+ m_directoryPathCompressor.setCallback([&](ClangBackEnd::DirectoryPathIds &&directoryPathIds) {
+ addChangedPathForFilePath(std::move(directoryPathIds));
});
}
~ClangPathWatcher()
{
- m_changedFilePathCompressor.setCallback([&] (FilePathIds &&) {});
+ m_directoryPathCompressor.setCallback([&](DirectoryPathIds &&) {});
}
void updateIdPaths(const std::vector<IdPaths> &idPaths) override
@@ -109,7 +132,7 @@ public:
auto filteredPaths = filterNotWatchedPaths(removedEntries);
if (!filteredPaths.empty())
- m_fileSystemWatcher.removePaths(convertWatcherEntriesToQStringList(filteredPaths));
+ m_fileSystemWatcher.removePaths(convertWatcherEntriesToDirectoryPathList(filteredPaths));
}
void setNotifier(ClangPathWatcherNotifier *notifier) override
@@ -164,7 +187,13 @@ public:
outputIterator = std::transform(idPath.filePathIds.begin(),
idPath.filePathIds.end(),
outputIterator,
- [&] (FilePathId pathId) { return WatcherEntry{id, pathId}; });
+ [&](FilePathId filePathId) {
+ return WatcherEntry{
+ id,
+ m_pathCache.directoryPathId(filePathId),
+ filePathId,
+ m_fileStatusCache.lastModifiedTime(filePathId)};
+ });
}
std::sort(entries.begin(), entries.end());
@@ -182,7 +211,7 @@ public:
mergeToWatchedEntries(newEntries);
if (!filteredPaths.empty())
- m_fileSystemWatcher.addPaths(convertWatcherEntriesToQStringList(filteredPaths));
+ m_fileSystemWatcher.addPaths(convertWatcherEntriesToDirectoryPathList(filteredPaths));
}
void removeUnusedEntries(const WatcherEntries &entries, const ProjectPartIds &ids)
@@ -194,33 +223,31 @@ public:
auto filteredPaths = filterNotWatchedPaths(oldEntries);
if (!filteredPaths.empty())
- m_fileSystemWatcher.removePaths(convertWatcherEntriesToQStringList(filteredPaths));
+ m_fileSystemWatcher.removePaths(convertWatcherEntriesToDirectoryPathList(filteredPaths));
}
- FileSystemWatcher &fileSystemWatcher()
+ FileSystemWatcher &fileSystemWatcher() { return m_fileSystemWatcher; }
+
+ QStringList convertWatcherEntriesToDirectoryPathList(const DirectoryPathIds &directoryPathIds) const
{
- return m_fileSystemWatcher;
+ return Utils::transform<QStringList>(directoryPathIds, [&](DirectoryPathId id) {
+ return QString(m_pathCache.directoryPath(id));
+ });
}
- QStringList convertWatcherEntriesToQStringList(
- const WatcherEntries &watcherEntries)
+ QStringList convertWatcherEntriesToDirectoryPathList(const WatcherEntries &watcherEntries) const
{
- QStringList paths;
- paths.reserve(int(watcherEntries.size()));
+ DirectoryPathIds directoryPathIds = Utils::transform<DirectoryPathIds>(
+ watcherEntries, [&](WatcherEntry entry) { return entry.directoryPathId; });
- std::transform(watcherEntries.begin(),
- watcherEntries.end(),
- std::back_inserter(paths),
- [&] (WatcherEntry entry) {
- return QString(m_pathCache.filePath(entry.pathId).path());
- });
+ std::sort(directoryPathIds.begin(), directoryPathIds.end());
+ directoryPathIds.erase(std::unique(directoryPathIds.begin(), directoryPathIds.end()),
+ directoryPathIds.end());
- return paths;
+ return convertWatcherEntriesToDirectoryPathList(directoryPathIds);
}
- template <typename Compare>
- WatcherEntries notWatchedEntries(const WatcherEntries &entries,
- Compare compare) const
+ WatcherEntries notWatchedEntries(const WatcherEntries &entries) const
{
WatcherEntries notWatchedEntries;
notWatchedEntries.reserve(entries.size());
@@ -229,24 +256,23 @@ public:
entries.end(),
m_watchedEntries.cbegin(),
m_watchedEntries.cend(),
- std::back_inserter(notWatchedEntries),
- compare);
+ std::back_inserter(notWatchedEntries));
return notWatchedEntries;
}
- WatcherEntries notWatchedEntries(const WatcherEntries &entries) const
+ DirectoryPathIds notWatchedPaths(const DirectoryPathIds &ids) const
{
- return notWatchedEntries(entries, std::less<WatcherEntry>());
- }
+ DirectoryPathIds notWatchedDirectoryIds;
+ notWatchedDirectoryIds.reserve(ids.size());
- WatcherEntries notWatchedPaths(const WatcherEntries &entries) const
- {
- auto compare = [] (WatcherEntry first, WatcherEntry second) {
- return first.pathId < second.pathId;
- };
+ std::set_difference(ids.begin(),
+ ids.end(),
+ m_watchedEntries.cbegin(),
+ m_watchedEntries.cend(),
+ std::back_inserter(notWatchedDirectoryIds));
- return notWatchedEntries(entries, compare);
+ return notWatchedDirectoryIds;
}
template <typename Compare>
@@ -297,25 +323,24 @@ public:
m_watchedEntries = std::move(newWatchedEntries);
}
- static
- WatcherEntries uniquePaths(const WatcherEntries &pathEntries)
+ static DirectoryPathIds uniquePaths(const WatcherEntries &pathEntries)
{
- WatcherEntries uniqueEntries;
- uniqueEntries.reserve(pathEntries.size());
+ DirectoryPathIds uniqueDirectoryIds;
+ uniqueDirectoryIds.reserve(pathEntries.size());
- auto compare = [] (WatcherEntry first, WatcherEntry second) {
- return first.pathId == second.pathId;
+ auto compare = [](WatcherEntry first, WatcherEntry second) {
+ return first.directoryPathId == second.directoryPathId;
};
std::unique_copy(pathEntries.begin(),
pathEntries.end(),
- std::back_inserter(uniqueEntries),
+ std::back_inserter(uniqueDirectoryIds),
compare);
- return uniqueEntries;
+ return uniqueDirectoryIds;
}
- WatcherEntries filterNotWatchedPaths(const WatcherEntries &entries)
+ DirectoryPathIds filterNotWatchedPaths(const WatcherEntries &entries) const
{
return notWatchedPaths(uniquePaths(entries));
}
@@ -351,40 +376,48 @@ public:
oldEntries.end(),
std::back_inserter(newWatchedEntries));
-
- m_watchedEntries = newWatchedEntries;
+ m_watchedEntries = std::move(newWatchedEntries);
}
- void compressChangedFilePath(const QString &filePath)
+ void compressChangedDirectoryPath(const QString &path)
{
- m_changedFilePathCompressor.addFilePath(filePath);
+ m_directoryPathCompressor.addDirectoryPathId(
+ m_pathCache.directoryPathId(Utils::PathString{path}));
}
- WatcherEntries watchedEntriesForPaths(ClangBackEnd::FilePathIds &&filePathIds)
+ WatcherEntries watchedEntriesForPaths(ClangBackEnd::DirectoryPathIds &&directoryPathIds)
{
WatcherEntries foundEntries;
- foundEntries.reserve(filePathIds.size());
-
- for (FilePathId pathId : filePathIds) {
- auto range = std::equal_range(m_watchedEntries.begin(), m_watchedEntries.end(), pathId);
- foundEntries.insert(foundEntries.end(), range.first, range.second);
- }
+ foundEntries.reserve(m_watchedEntries.size());
+
+ set_greedy_intersection_call(m_watchedEntries.begin(),
+ m_watchedEntries.end(),
+ directoryPathIds.begin(),
+ directoryPathIds.end(),
+ [&](WatcherEntry &entry) {
+ m_fileStatusCache.update(entry.filePathId);
+ auto currentLastModified = m_fileStatusCache.lastModifiedTime(
+ entry.filePathId);
+ if (entry.lastModified < currentLastModified) {
+ foundEntries.push_back(entry);
+ entry.lastModified = currentLastModified;
+ }
+ });
return foundEntries;
}
- FilePathIds watchedPaths(const FilePathIds &filePathIds) const
+ FilePathIds watchedPaths(const WatcherEntries &entries) const
{
- FilePathIds watchedFilePathIds;
- watchedFilePathIds.reserve(filePathIds.size());
+ auto filePathIds = Utils::transform<FilePathIds>(entries, [](WatcherEntry entry) {
+ return entry.filePathId;
+ });
+
+ std::sort(filePathIds.begin(), filePathIds.end());
- std::set_intersection(m_watchedEntries.begin(),
- m_watchedEntries.end(),
- filePathIds.begin(),
- filePathIds.end(),
- std::back_inserter(watchedFilePathIds));
+ filePathIds.erase(std::unique(filePathIds.begin(), filePathIds.end()), filePathIds.end());
- return watchedFilePathIds;
+ return filePathIds;
}
ProjectPartIds idsForWatcherEntries(const WatcherEntries &foundEntries)
@@ -403,21 +436,20 @@ public:
ProjectPartIds uniqueIds(ProjectPartIds &&ids)
{
std::sort(ids.begin(), ids.end());
- auto newEnd = std::unique(ids.begin(), ids.end());
- ids.erase(newEnd, ids.end());
+ ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
return std::move(ids);
}
- void addChangedPathForFilePath(FilePathIds &&filePathIds)
+ void addChangedPathForFilePath(DirectoryPathIds &&directoryPathIds)
{
if (m_notifier) {
- WatcherEntries foundEntries = watchedEntriesForPaths(std::move(filePathIds));
+ WatcherEntries foundEntries = watchedEntriesForPaths(std::move(directoryPathIds));
ProjectPartIds changedIds = idsForWatcherEntries(foundEntries);
m_notifier->pathsWithIdsChanged(uniqueIds(std::move(changedIds)));
- m_notifier->pathsChanged(watchedPaths(filePathIds));
+ m_notifier->pathsChanged(watchedPaths(foundEntries));
}
}
@@ -428,10 +460,12 @@ public:
private:
WatcherEntries m_watchedEntries;
- ChangedFilePathCompressor<Timer> m_changedFilePathCompressor;
FileSystemWatcher m_fileSystemWatcher;
+ FileStatusCache m_fileStatusCache;
+ FileSystemInterface &m_fileSystem;
FilePathCachingInterface &m_pathCache;
ClangPathWatcherNotifier *m_notifier;
+ DirectoryPathCompressor<Timer> m_directoryPathCompressor;
};
} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/clangsupport-lib.pri b/src/libs/clangsupport/clangsupport-lib.pri
index df537f5848..dc66408e58 100644
--- a/src/libs/clangsupport/clangsupport-lib.pri
+++ b/src/libs/clangsupport/clangsupport-lib.pri
@@ -18,6 +18,7 @@ SOURCES += \
$$PWD/clangcodemodelserverproxy.cpp \
$$PWD/alivemessage.cpp \
$$PWD/completionsmessage.cpp \
+ $$PWD/filesystem.cpp \
$$PWD/requestcompletionsmessage.cpp \
$$PWD/echomessage.cpp \
$$PWD/endmessage.cpp \
@@ -87,7 +88,8 @@ SOURCES += \
$$PWD/removegeneratedfilesmessage.cpp \
$$PWD/generatedfiles.cpp \
$$PWD/projectpartartefact.cpp \
- $$PWD/projectpartcontainer.cpp
+ $$PWD/projectpartcontainer.cpp \
+ $$PWD/filestatuscache.cpp
HEADERS += \
$$PWD/cancelmessage.h \
@@ -109,7 +111,11 @@ HEADERS += \
$$PWD/alivemessage.h \
$$PWD/clangsupportexceptions.h \
$$PWD/completionsmessage.h \
+ $$PWD/directoryandfilepathid.h \
+ $$PWD/directorypathid.h \
$$PWD/executeinloop.h \
+ $$PWD/filesystem.h \
+ $$PWD/filesysteminterface.h \
$$PWD/pchpaths.h \
$$PWD/projectpartid.h \
$$PWD/projectpartsstorage.h \
@@ -151,6 +157,7 @@ HEADERS += \
$$PWD/refactoringserverinterface.h \
$$PWD/refactoringserverproxy.h \
$$PWD/referencesmessage.h \
+ $$PWD/set_algorithm.h \
$$PWD/unsavedfilesupdatedmessage.h \
$$PWD/removeprojectpartsmessage.h \
$$PWD/requestannotationsmessage.h \
@@ -217,6 +224,8 @@ HEADERS += \
$$PWD/sourceentry.h \
$$PWD/modifiedtimecheckerinterface.h \
$$PWD/environment.h \
+ $$PWD/filestatus.h \
+ $$PWD/filestatuscache.h \
$$PWD/modifiedtimechecker.h
contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols
diff --git a/src/libs/clangsupport/directoryandfilepathid.h b/src/libs/clangsupport/directoryandfilepathid.h
new file mode 100644
index 0000000000..8969372919
--- /dev/null
+++ b/src/libs/clangsupport/directoryandfilepathid.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "directorypathid.h"
+#include "filepathid.h"
+
+#include <QDataStream>
+
+#include <vector>
+
+namespace ClangBackEnd {
+class DirectoryAndFilePathId
+{
+public:
+ constexpr DirectoryAndFilePathId() = default;
+
+ DirectoryAndFilePathId(const char *) = delete;
+
+ DirectoryAndFilePathId(int directoryPathId, int filePathId)
+ : directoryPathId(directoryPathId)
+ , filePathId(filePathId)
+ {}
+
+ bool isValid() const { return directoryPathId.isValid() && filePathId.isValid(); }
+
+ friend bool operator==(DirectoryAndFilePathId first, DirectoryAndFilePathId second)
+ {
+ return first.isValid() && first.directoryPathId == second.directoryPathId
+ && first.filePathId == second.filePathId;
+ }
+
+ friend bool operator!=(DirectoryAndFilePathId first, DirectoryAndFilePathId second)
+ {
+ return !(first == second);
+ }
+
+ friend bool operator<(DirectoryAndFilePathId first, DirectoryAndFilePathId second)
+ {
+ return std::tie(first.directoryPathId, first.filePathId)
+ < std::tie(second.directoryPathId, second.filePathId);
+ }
+
+ friend QDataStream &operator<<(QDataStream &out,
+ const DirectoryAndFilePathId &directoryAndFilePathId)
+ {
+ out << directoryAndFilePathId.directoryPathId;
+ out << directoryAndFilePathId.filePathId;
+
+ return out;
+ }
+
+ friend QDataStream &operator>>(QDataStream &in, DirectoryAndFilePathId &directoryAndFilePathId)
+ {
+ in >> directoryAndFilePathId.directoryPathId;
+ in >> directoryAndFilePathId.filePathId;
+ return in;
+ }
+
+public:
+ DirectoryPathId directoryPathId;
+ FilePathId filePathId;
+};
+
+using DirectoryAndFilePathIds = std::vector<DirectoryAndFilePathId>;
+
+} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/changedfilepathcompressor.h b/src/libs/clangsupport/directorypathcompressor.h
index aa8e1ec71a..cd02948e83 100644
--- a/src/libs/clangsupport/changedfilepathcompressor.h
+++ b/src/libs/clangsupport/directorypathcompressor.h
@@ -27,53 +27,44 @@
#include "clangsupport_global.h"
-#include <filepathid.h>
-#include <filepathcache.h>
+#include "filepathcachinginterface.h"
+#include <QDir>
#include <QTimer>
-#include <filepathcachinginterface.h>
+#include <utils/algorithm.h>
#include <functional>
namespace ClangBackEnd {
-template <typename Timer>
-class ChangedFilePathCompressor
+template<typename Timer>
+class DirectoryPathCompressor
{
public:
- ChangedFilePathCompressor(FilePathCachingInterface &filePathCache)
- : m_filePathCache(filePathCache)
- {
- m_timer.setSingleShot(true);
- }
+ DirectoryPathCompressor() { m_timer.setSingleShot(true); }
- virtual ~ChangedFilePathCompressor()
- {
- }
+ virtual ~DirectoryPathCompressor() = default;
- void addFilePath(const QString &filePath)
+ void addDirectoryPathId(DirectoryPathId directoryPathIdId)
{
- FilePathId filePathId = m_filePathCache.filePathId(FilePath(filePath));
+ auto found = std::lower_bound(m_directoryPathIds.begin(),
+ m_directoryPathIds.end(),
+ directoryPathIdId);
- auto found = std::lower_bound(m_filePaths.begin(), m_filePaths.end(), filePathId);
-
- if (found == m_filePaths.end() || *found != filePathId)
- m_filePaths.insert(found, filePathId);
+ if (found == m_directoryPathIds.end() || *found != directoryPathIdId)
+ m_directoryPathIds.insert(found, directoryPathIdId);
restartTimer();
}
- FilePathIds takeFilePathIds()
- {
- return std::move(m_filePaths);
- }
+ DirectoryPathIds takeDirectoryPathIds() { return std::move(m_directoryPathIds); }
- virtual void setCallback(std::function<void(ClangBackEnd::FilePathIds &&)> &&callback)
+ virtual void setCallback(std::function<void(ClangBackEnd::DirectoryPathIds &&)> &&callback)
{
- QObject::connect(&m_timer,
- &Timer::timeout,
- [this, callback=std::move(callback)] { callback(takeFilePathIds()); });
+ QObject::connect(&m_timer, &Timer::timeout, [this, callback = std::move(callback)] {
+ callback(takeDirectoryPathIds());
+ });
}
unittest_public:
@@ -88,9 +79,8 @@ unittest_public:
}
private:
- FilePathIds m_filePaths;
+ DirectoryPathIds m_directoryPathIds;
Timer m_timer;
- FilePathCachingInterface &m_filePathCache;
};
} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/directorypathid.h b/src/libs/clangsupport/directorypathid.h
new file mode 100644
index 0000000000..2fd0b5847e
--- /dev/null
+++ b/src/libs/clangsupport/directorypathid.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 <QDataStream>
+
+#include <vector>
+
+namespace ClangBackEnd {
+class DirectoryPathId
+{
+public:
+ constexpr DirectoryPathId() = default;
+
+ DirectoryPathId(const char *) = delete;
+
+ DirectoryPathId(int directoryPathId)
+ : directoryPathId(directoryPathId)
+ {}
+
+ bool isValid() const { return directoryPathId >= 0; }
+
+ friend bool operator==(DirectoryPathId first, DirectoryPathId second)
+ {
+ return first.isValid() && first.directoryPathId == second.directoryPathId;
+ }
+
+ friend bool operator!=(DirectoryPathId first, DirectoryPathId second)
+ {
+ return !(first == second);
+ }
+
+ friend bool operator<(DirectoryPathId first, DirectoryPathId second)
+ {
+ return first.directoryPathId < second.directoryPathId;
+ }
+
+ friend QDataStream &operator<<(QDataStream &out, const DirectoryPathId &directoryPathId)
+ {
+ out << directoryPathId.directoryPathId;
+
+ return out;
+ }
+
+ friend QDataStream &operator>>(QDataStream &in, DirectoryPathId &directoryPathId)
+ {
+ in >> directoryPathId.directoryPathId;
+
+ return in;
+ }
+
+public:
+ int directoryPathId = -1;
+};
+
+using DirectoryPathIds = std::vector<DirectoryPathId>;
+
+} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/filepathcache.h b/src/libs/clangsupport/filepathcache.h
index bdd925a79c..4845416d22 100644
--- a/src/libs/clangsupport/filepathcache.h
+++ b/src/libs/clangsupport/filepathcache.h
@@ -25,9 +25,10 @@
#pragma once
+#include "directorypathid.h"
+#include "filepath.h"
#include "filepathexceptions.h"
#include "filepathid.h"
-#include "filepath.h"
#include "filepathview.h"
#include "stringcache.h"
@@ -121,10 +122,10 @@ public:
{
Utils::SmallStringView directoryPath = filePath.directory();
- int directoryId = m_directoryPathCache.stringId(directoryPath,
- [&] (const Utils::SmallStringView) {
- return m_filePathStorage.fetchDirectoryId(directoryPath);
- });
+ int directoryId = m_directoryPathCache.stringId(
+ directoryPath, [&](const Utils::SmallStringView directoryPath) {
+ return m_filePathStorage.fetchDirectoryId(directoryPath);
+ });
Utils::SmallStringView fileName = filePath.name();
@@ -136,6 +137,17 @@ public:
return fileNameId;
}
+ DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const
+ {
+ Utils::SmallStringView path = directoryPath.back() == '/'
+ ? directoryPath.mid(0, directoryPath.size() - 1)
+ : directoryPath;
+
+ return m_directoryPathCache.stringId(path, [&](const Utils::SmallStringView directoryPath) {
+ return m_filePathStorage.fetchDirectoryId(directoryPath);
+ });
+ }
+
FilePath filePath(FilePathId filePathId) const
{
if (Q_UNLIKELY(!filePathId.isValid()))
@@ -157,6 +169,32 @@ public:
return FilePath{directoryPath, entry.fileName};
}
+ Utils::PathString directoryPath(DirectoryPathId directoryPathId) const
+ {
+ if (Q_UNLIKELY(!directoryPathId.isValid()))
+ throw NoDirectoryPathForInvalidDirectoryPathId();
+
+ auto fetchDirectoryPath = [&](int id) { return m_filePathStorage.fetchDirectoryPath(id); };
+
+ return m_directoryPathCache.string(directoryPathId.directoryPathId, fetchDirectoryPath);
+ }
+
+ DirectoryPathId directoryPathId(FilePathId filePathId) const
+ {
+ if (Q_UNLIKELY(!filePathId.isValid()))
+ throw NoFilePathForInvalidFilePathId();
+
+ auto fetchSoureNameAndDirectoryId = [&](int id) {
+ auto entry = m_filePathStorage.fetchSourceNameAndDirectoryId(id);
+ return FileNameEntry{entry.sourceName, entry.directoryId};
+ };
+
+ FileNameEntry entry = m_fileNameCache.string(filePathId.filePathId,
+ fetchSoureNameAndDirectoryId);
+
+ return m_fileNameCache.string(filePathId.filePathId, fetchSoureNameAndDirectoryId).directoryId;
+ }
+
private:
mutable DirectoryPathCache m_directoryPathCache;
mutable FileNameCache m_fileNameCache;
diff --git a/src/libs/clangsupport/filepathcaching.cpp b/src/libs/clangsupport/filepathcaching.cpp
index 0a3fc6ee41..372ed86bd3 100644
--- a/src/libs/clangsupport/filepathcaching.cpp
+++ b/src/libs/clangsupport/filepathcaching.cpp
@@ -37,4 +37,19 @@ FilePath FilePathCaching::filePath(FilePathId filePathId) const
return m_cache.filePath(filePathId);
}
+DirectoryPathId FilePathCaching::directoryPathId(Utils::SmallStringView directoryPath) const
+{
+ return m_cache.directoryPathId(directoryPath);
+}
+
+Utils::PathString FilePathCaching::directoryPath(DirectoryPathId directoryPathId) const
+{
+ return m_cache.directoryPath(directoryPathId);
+}
+
+DirectoryPathId FilePathCaching::directoryPathId(FilePathId filePathId) const
+{
+ return m_cache.directoryPathId(filePathId);
+}
+
} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/filepathcaching.h b/src/libs/clangsupport/filepathcaching.h
index a3337755fd..f69b940b15 100644
--- a/src/libs/clangsupport/filepathcaching.h
+++ b/src/libs/clangsupport/filepathcaching.h
@@ -50,6 +50,9 @@ public:
FilePathId filePathId(FilePathView filePath) const override;
FilePath filePath(FilePathId filePathId) const override;
+ DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const override;
+ Utils::PathString directoryPath(DirectoryPathId directoryPathId) const override;
+ DirectoryPathId directoryPathId(FilePathId filePathId) const override;
private:
Factory m_factory;
diff --git a/src/libs/clangsupport/filepathcachinginterface.h b/src/libs/clangsupport/filepathcachinginterface.h
index b9668362f7..098fd39ca9 100644
--- a/src/libs/clangsupport/filepathcachinginterface.h
+++ b/src/libs/clangsupport/filepathcachinginterface.h
@@ -25,6 +25,7 @@
#pragma once
+#include "directorypathid.h"
#include "filepath.h"
#include "filepathid.h"
#include "filepathview.h"
@@ -40,8 +41,11 @@ public:
virtual FilePathId filePathId(FilePathView filePath) const = 0;
virtual FilePath filePath(FilePathId filePathId) const = 0;
+ virtual DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const = 0;
+ virtual DirectoryPathId directoryPathId(FilePathId filePathId) const = 0;
+ virtual Utils::PathString directoryPath(DirectoryPathId directoryPathId) const = 0;
- template <typename Container>
+ template<typename Container>
FilePathIds filePathIds(Container &&filePaths) const
{
FilePathIds filePathIds;
diff --git a/src/libs/clangsupport/filepathexceptions.h b/src/libs/clangsupport/filepathexceptions.h
index 80bded0c66..3174d89479 100644
--- a/src/libs/clangsupport/filepathexceptions.h
+++ b/src/libs/clangsupport/filepathexceptions.h
@@ -38,6 +38,15 @@ public:
}
};
+class NoDirectoryPathForInvalidDirectoryPathId : std::exception
+{
+public:
+ const char *what() const noexcept override
+ {
+ return "You cannot get a directory path for an invalid directory path id!";
+ }
+};
+
class SourceNameIdDoesNotExists : std::exception
{
public:
diff --git a/src/libs/clangsupport/filepathstorage.h b/src/libs/clangsupport/filepathstorage.h
index 5917504dbf..8aba2ef6d2 100644
--- a/src/libs/clangsupport/filepathstorage.h
+++ b/src/libs/clangsupport/filepathstorage.h
@@ -179,12 +179,32 @@ public:
transaction.commit();
- return optionalSourceName.value();
+ return *optionalSourceName;
} catch (const Sqlite::StatementIsBusy &) {
return fetchSourceNameAndDirectoryId(sourceId);
}
}
+ int fetchDirectoryId(int sourceId)
+ {
+ try {
+ Sqlite::DeferredTransaction transaction{m_statementFactory.database};
+
+ ReadStatement &statement = m_statementFactory.selectDirectoryIdFromSourcesBySourceId;
+
+ auto optionalDirectoryId = statement.template value<int>(sourceId);
+
+ if (!optionalDirectoryId)
+ throw SourceNameIdDoesNotExists();
+
+ transaction.commit();
+
+ return *optionalDirectoryId;
+ } catch (const Sqlite::StatementIsBusy &) {
+ return fetchDirectoryId(sourceId);
+ }
+ }
+
std::vector<Sources::Source> fetchAllSources()
{
try {
diff --git a/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h b/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h
index dbf8071775..27296a1df6 100644
--- a/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h
+++ b/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h
@@ -69,6 +69,8 @@ public:
"SELECT sourceName, directoryId FROM sources WHERE sourceId = ?",
database
};
+ ReadStatement selectDirectoryIdFromSourcesBySourceId{
+ "SELECT directoryId FROM sources WHERE sourceId = ?", database};
WriteStatement insertIntoSources{
"INSERT INTO sources(directoryId, sourceName) VALUES (?,?)",
database
diff --git a/src/libs/clangsupport/filestatus.h b/src/libs/clangsupport/filestatus.h
new file mode 100644
index 0000000000..da2be4a304
--- /dev/null
+++ b/src/libs/clangsupport/filestatus.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <filepathid.h>
+
+#include <ctime>
+#include <sys/types.h>
+#include <vector>
+
+namespace ClangBackEnd {
+
+class FileStatus
+{
+public:
+ FileStatus(FilePathId filePathId, off_t size, std::time_t lastModified)
+ : filePathId(filePathId), size(size), lastModified(lastModified) {}
+
+ friend
+ bool operator==(const FileStatus &first, const FileStatus &second)
+ {
+ return first.filePathId == second.filePathId
+ && first.size == second.size
+ && first.lastModified == second.lastModified;
+ }
+
+ friend
+ bool operator<(const FileStatus &first, const FileStatus &second)
+ {
+ return first.filePathId < second.filePathId;
+ }
+
+public:
+ FilePathId filePathId;
+ off_t size;
+ std::time_t lastModified;
+};
+
+using FileStatuses = std::vector<FileStatus>;
+}
diff --git a/src/libs/clangsupport/filestatuscache.cpp b/src/libs/clangsupport/filestatuscache.cpp
new file mode 100644
index 0000000000..e8ed50a833
--- /dev/null
+++ b/src/libs/clangsupport/filestatuscache.cpp
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "filestatuscache.h"
+#include "filesystem.h"
+
+#include <set_algorithm.h>
+
+#include <utils/algorithm.h>
+
+#include <QDateTime>
+#include <QFileInfo>
+
+namespace ClangBackEnd {
+
+long long FileStatusCache::lastModifiedTime(FilePathId filePathId) const
+{
+ return findEntry(filePathId).lastModified;
+}
+
+void FileStatusCache::update(FilePathId filePathId)
+{
+ auto found = std::lower_bound(m_cacheEntries.begin(),
+ m_cacheEntries.end(),
+ Internal::FileStatusCacheEntry{filePathId},
+ [] (const auto &first, const auto &second) {
+ return first.filePathId < second.filePathId;
+ });
+
+ if (found != m_cacheEntries.end() && found->filePathId == filePathId)
+ found->lastModified = m_fileSystem.lastModified(filePathId);
+}
+
+void FileStatusCache::update(FilePathIds filePathIds)
+{
+ std::set_intersection(m_cacheEntries.begin(),
+ m_cacheEntries.end(),
+ filePathIds.begin(),
+ filePathIds.end(),
+ make_iterator([&](auto &entry) {
+ entry.lastModified = m_fileSystem.lastModified(entry.filePathId);
+ }));
+}
+
+FilePathIds FileStatusCache::modified(FilePathIds filePathIds) const
+{
+ FilePathIds modifiedFilePathIds;
+ modifiedFilePathIds.reserve(filePathIds.size());
+
+ std::set_intersection(m_cacheEntries.begin(),
+ m_cacheEntries.end(),
+ filePathIds.begin(),
+ filePathIds.end(),
+ make_iterator([&](auto &entry) {
+ auto newLastModified = m_fileSystem.lastModified(entry.filePathId);
+ if (newLastModified > entry.lastModified) {
+ modifiedFilePathIds.push_back(entry.filePathId);
+ entry.lastModified = newLastModified;
+ }
+ }));
+
+ Internal::FileStatusCacheEntries newEntries;
+ newEntries.reserve(filePathIds.size());
+
+ std::set_difference(filePathIds.begin(),
+ filePathIds.end(),
+ m_cacheEntries.begin(),
+ m_cacheEntries.end(),
+ make_iterator([&](FilePathId newFilePathId) {
+ newEntries.emplace_back(newFilePathId,
+ m_fileSystem.lastModified(newFilePathId));
+ modifiedFilePathIds.push_back(newFilePathId);
+ }));
+
+ if (newEntries.size()) {
+ Internal::FileStatusCacheEntries mergedEntries;
+ mergedEntries.reserve(m_cacheEntries.size() + newEntries.size());
+
+ std::set_union(newEntries.begin(),
+ newEntries.end(),
+ m_cacheEntries.begin(),
+ m_cacheEntries.end(),
+ std::back_inserter(mergedEntries));
+
+ m_cacheEntries = std::move(mergedEntries);
+ }
+
+ std::sort(modifiedFilePathIds.begin(), modifiedFilePathIds.end());
+
+ return modifiedFilePathIds;
+}
+
+FileStatusCache::size_type FileStatusCache::size() const
+{
+ return m_cacheEntries.size();
+}
+
+Internal::FileStatusCacheEntry FileStatusCache::findEntry(FilePathId filePathId) const
+{
+ auto found = std::lower_bound(m_cacheEntries.begin(),
+ m_cacheEntries.end(),
+ Internal::FileStatusCacheEntry{filePathId},
+ [] (const auto &first, const auto &second) {
+ return first.filePathId < second.filePathId;
+ });
+
+ if (found != m_cacheEntries.end() && found->filePathId == filePathId)
+ return *found;
+
+ auto inserted = m_cacheEntries.emplace(found, filePathId, m_fileSystem.lastModified(filePathId));
+
+ return *inserted;
+}
+
+} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/filestatuscache.h b/src/libs/clangsupport/filestatuscache.h
new file mode 100644
index 0000000000..3f0af56b3a
--- /dev/null
+++ b/src/libs/clangsupport/filestatuscache.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <filepathcachinginterface.h>
+
+QT_FORWARD_DECLARE_CLASS(QFileInfo)
+
+namespace ClangBackEnd {
+
+class FileSystemInterface;
+
+namespace Internal {
+class FileStatusCacheEntry
+{
+public:
+ FileStatusCacheEntry(ClangBackEnd::FilePathId filePathId,
+ long long lastModified = 0)
+ : filePathId(filePathId),
+ lastModified(lastModified)
+ {}
+
+ friend bool operator<(FileStatusCacheEntry first, FileStatusCacheEntry second)
+ {
+ return first.filePathId < second.filePathId;
+ }
+
+ friend bool operator<(FileStatusCacheEntry first, FilePathId second)
+ {
+ return first.filePathId < second;
+ }
+
+ friend bool operator<(FilePathId first, FileStatusCacheEntry second)
+ {
+ return first < second.filePathId;
+ }
+
+public:
+ FilePathId filePathId;
+ long long lastModified;
+};
+
+using FileStatusCacheEntries = std::vector<FileStatusCacheEntry>;
+
+}
+
+class CLANGSUPPORT_EXPORT FileStatusCache
+{
+public:
+ using size_type = Internal::FileStatusCacheEntries::size_type;
+
+ FileStatusCache(FileSystemInterface &fileSystem)
+ : m_fileSystem(fileSystem)
+ {}
+ FileStatusCache &operator=(const FileStatusCache &) = delete;
+ FileStatusCache(const FileStatusCache &) = delete;
+
+ long long lastModifiedTime(FilePathId filePathId) const;
+ void update(FilePathId filePathId);
+ void update(FilePathIds filePathIds);
+ FilePathIds modified(FilePathIds filePathIds) const;
+
+ size_type size() const;
+
+private:
+ Internal::FileStatusCacheEntry findEntry(FilePathId filePathId) const;
+
+private:
+ mutable Internal::FileStatusCacheEntries m_cacheEntries;
+ FileSystemInterface &m_fileSystem;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/filesystem.cpp b/src/libs/clangsupport/filesystem.cpp
new file mode 100644
index 0000000000..5b8c037f80
--- /dev/null
+++ b/src/libs/clangsupport/filesystem.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "filesystem.h"
+#include "filepathcachinginterface.h"
+
+#include <utils/algorithm.h>
+
+#include <QDateTime>
+#include <QDir>
+#include <QFileInfo>
+
+namespace ClangBackEnd {
+
+FilePathIds FileSystem::directoryEntries(const QString &directoryPath) const
+{
+ QDir directory{directoryPath};
+
+ QFileInfoList fileInfos = directory.entryInfoList();
+
+ FilePathIds filePathIds = Utils::transform<FilePathIds>(fileInfos, [&](const QFileInfo &fileInfo) {
+ return m_filePathCache.filePathId(FilePath{fileInfo.path()});
+ });
+
+ std::sort(filePathIds.begin(), filePathIds.end());
+
+ return filePathIds;
+}
+
+long long FileSystem::lastModified(FilePathId filePathId) const
+{
+ QFileInfo fileInfo(QString(m_filePathCache.filePath(filePathId)));
+
+ fileInfo.refresh();
+
+ return fileInfo.lastModified().toMSecsSinceEpoch() / 1000;
+}
+
+} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/filesystem.h b/src/libs/clangsupport/filesystem.h
new file mode 100644
index 0000000000..ecf332de55
--- /dev/null
+++ b/src/libs/clangsupport/filesystem.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "filestatuscache.h"
+#include "filesysteminterface.h"
+
+namespace ClangBackEnd {
+class FilePathCachingInterface;
+
+class CLANGSUPPORT_EXPORT FileSystem final : public FileSystemInterface
+{
+public:
+ FileSystem(FilePathCachingInterface &filePathCache)
+ : m_filePathCache(filePathCache)
+ {}
+
+ FilePathIds directoryEntries(const QString &directoryPath) const override;
+ long long lastModified(FilePathId filePathId) const override;
+
+private:
+ FilePathCachingInterface &m_filePathCache;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/filesysteminterface.h b/src/libs/clangsupport/filesysteminterface.h
new file mode 100644
index 0000000000..9d64d2a93a
--- /dev/null
+++ b/src/libs/clangsupport/filesysteminterface.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "filepathid.h"
+
+#include <utils/smallstringview.h>
+
+namespace ClangBackEnd {
+
+class FileSystemInterface
+{
+public:
+ virtual FilePathIds directoryEntries(const QString &directoryPath) const = 0;
+ virtual long long lastModified(FilePathId filePathId) const = 0;
+
+protected:
+ ~FileSystemInterface() = default;
+};
+} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/modifiedtimechecker.h b/src/libs/clangsupport/modifiedtimechecker.h
index c9b62c4673..00e8e3ebac 100644
--- a/src/libs/clangsupport/modifiedtimechecker.h
+++ b/src/libs/clangsupport/modifiedtimechecker.h
@@ -25,23 +25,23 @@
#pragma once
-#include "filepathcachinginterface.h"
+#include "filesysteminterface.h"
#include "modifiedtimecheckerinterface.h"
+#include "set_algorithm.h"
#include <algorithm>
#include <iterator>
namespace ClangBackEnd {
+
template<typename SourceEntries = ::ClangBackEnd::SourceEntries>
class ModifiedTimeChecker final : public ModifiedTimeCheckerInterface<SourceEntries>
{
using SourceEntry = typename SourceEntries::value_type;
public:
- using GetModifiedTime = std::function<ClangBackEnd::TimeStamp(ClangBackEnd::FilePathView filePath)>;
- ModifiedTimeChecker(GetModifiedTime &getModifiedTime, FilePathCachingInterface &filePathCache)
- : m_getModifiedTime(getModifiedTime)
- , m_filePathCache(filePathCache)
+ ModifiedTimeChecker(FileSystemInterface &fileSystem)
+ : m_fileSystem(fileSystem)
{}
bool isUpToDate(const SourceEntries &sourceEntries) const
@@ -51,165 +51,101 @@ public:
updateCurrentSourceTimeStamps(sourceEntries);
- return compareEntries(sourceEntries);
+ return compareEntries(sourceEntries) && notReseted(sourceEntries);
}
- void pathsChanged(const FilePathIds &filePathIds)
+ void pathsChanged(const FilePathIds &filePathIds) override
{
- using SourceTimeStampReferences = std::vector<std::reference_wrapper<SourceTimeStamp>>;
-
- SourceTimeStampReferences timeStampsToUpdate;
- timeStampsToUpdate.reserve(filePathIds.size());
-
std::set_intersection(m_currentSourceTimeStamps.begin(),
m_currentSourceTimeStamps.end(),
filePathIds.begin(),
filePathIds.end(),
- std::back_inserter(timeStampsToUpdate));
+ make_iterator([&](SourceTimeStamp &sourceTimeStamp) {
+ sourceTimeStamp.timeStamp = m_fileSystem.lastModified(
+ sourceTimeStamp.sourceId);
+ }));
+ }
+
+ void reset(const FilePathIds &filePathIds)
+ {
+ FilePathIds newResetFilePathIds;
+ newResetFilePathIds.reserve(newResetFilePathIds.size() + m_resetFilePathIds.size());
+
+ std::set_union(m_resetFilePathIds.begin(),
+ m_resetFilePathIds.end(),
+ filePathIds.begin(),
+ filePathIds.end(),
+ std::back_inserter(newResetFilePathIds));
- for (SourceTimeStamp &sourceTimeStamp : timeStampsToUpdate) {
- sourceTimeStamp.timeStamp = m_getModifiedTime(
- m_filePathCache.filePath(sourceTimeStamp.sourceId));
- }
+ m_resetFilePathIds = std::move(newResetFilePathIds);
}
private:
bool compareEntries(const SourceEntries &sourceEntries) const
{
- class CompareSourceId
- {
- public:
- bool operator()(SourceTimeStamp first, SourceTimeStamp second)
- {
- return first.sourceId < second.sourceId;
- }
-
- bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second)
- {
- return first.sourceId < second.sourceId;
- }
-
- bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second)
- {
- return first.sourceId < second.sourceId;
- }
-
- bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second)
- {
- return first.sourceId < second.sourceId;
- }
- };
-
- SourceTimeStamps currentSourceTimeStamp;
- currentSourceTimeStamp.reserve(sourceEntries.size());
- std::set_intersection(m_currentSourceTimeStamps.begin(),
- m_currentSourceTimeStamps.end(),
- sourceEntries.begin(),
- sourceEntries.end(),
- std::back_inserter(currentSourceTimeStamp),
- CompareSourceId{});
-
- class CompareTime
- {
- public:
- bool operator()(SourceTimeStamp first, SourceTimeStamp second)
- {
- return first.timeStamp <= second.timeStamp;
- }
-
- bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second)
- {
- return first.timeStamp <= second.timeStamp;
- }
-
- bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second)
- {
- return first.timeStamp <= second.timeStamp;
- }
-
- bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second)
- {
- return first.timeStamp <= second.timeStamp;
- }
- };
-
- return std::lexicographical_compare(currentSourceTimeStamp.begin(),
- currentSourceTimeStamp.end(),
- sourceEntries.begin(),
- sourceEntries.end(),
- CompareTime{});
+ return set_intersection_compare(
+ m_currentSourceTimeStamps.begin(),
+ m_currentSourceTimeStamps.end(),
+ sourceEntries.begin(),
+ sourceEntries.end(),
+ [](auto first, auto second) { return second.timeStamp > first.timeStamp; },
+ [](auto first, auto second) { return first.sourceId < second.sourceId; });
}
void updateCurrentSourceTimeStamps(const SourceEntries &sourceEntries) const
{
SourceTimeStamps sourceTimeStamps = newSourceTimeStamps(sourceEntries);
- for (SourceTimeStamp &newSourceTimeStamp : sourceTimeStamps) {
- newSourceTimeStamp.timeStamp = m_getModifiedTime(
- m_filePathCache.filePath(newSourceTimeStamp.sourceId));
- }
-
auto split = sourceTimeStamps.insert(sourceTimeStamps.end(),
m_currentSourceTimeStamps.begin(),
m_currentSourceTimeStamps.end());
std::inplace_merge(sourceTimeStamps.begin(), split, sourceTimeStamps.end());
- m_currentSourceTimeStamps = sourceTimeStamps;
+ m_currentSourceTimeStamps = std::move(sourceTimeStamps);
}
SourceTimeStamps newSourceTimeStamps(const SourceEntries &sourceEntries) const
{
- SourceEntries newSourceEntries;
- newSourceEntries.reserve(sourceEntries.size());
-
- class CompareSourceId
- {
- public:
- bool operator()(SourceTimeStamp first, SourceTimeStamp second)
- {
- return first.sourceId < second.sourceId;
- }
-
- bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second)
- {
- return first.sourceId < second.sourceId;
- }
-
- bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second)
- {
- return first.sourceId < second.sourceId;
- }
-
- bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second)
- {
- return first.sourceId < second.sourceId;
- }
- };
+ SourceTimeStamps newTimeStamps;
+ newTimeStamps.reserve(sourceEntries.size());
std::set_difference(sourceEntries.begin(),
sourceEntries.end(),
m_currentSourceTimeStamps.begin(),
m_currentSourceTimeStamps.end(),
- std::back_inserter(newSourceEntries),
- CompareSourceId{});
+ make_iterator([&](const SourceEntry &sourceEntry) {
+ newTimeStamps.emplace_back(sourceEntry.sourceId,
+ m_fileSystem.lastModified(
+ sourceEntry.sourceId));
+ }),
+ [](auto first, auto second) {
+ return first.sourceId < second.sourceId && first.timeStamp > 0;
+ });
- SourceTimeStamps newTimeStamps;
- newTimeStamps.reserve(newSourceEntries.size());
+ return newTimeStamps;
+ }
- std::transform(newSourceEntries.begin(),
- newSourceEntries.end(),
- std::back_inserter(newTimeStamps),
- [](SourceEntry entry) {
- return SourceTimeStamp{entry.sourceId, {}};
- });
+ bool notReseted(const SourceEntries &sourceEntries) const
+ {
+ auto oldSize = m_resetFilePathIds.size();
+ FilePathIds newResetFilePathIds;
+ newResetFilePathIds.reserve(newResetFilePathIds.size());
- return newTimeStamps;
+ std::set_difference(m_resetFilePathIds.begin(),
+ m_resetFilePathIds.end(),
+ sourceEntries.begin(),
+ sourceEntries.end(),
+ std::back_inserter(newResetFilePathIds));
+
+ m_resetFilePathIds = std::move(newResetFilePathIds);
+
+ return oldSize == m_resetFilePathIds.size();
}
private:
mutable SourceTimeStamps m_currentSourceTimeStamps;
- GetModifiedTime &m_getModifiedTime;
- FilePathCachingInterface &m_filePathCache;
+ mutable FilePathIds m_resetFilePathIds;
+ FileSystemInterface &m_fileSystem;
};
} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/modifiedtimecheckerinterface.h b/src/libs/clangsupport/modifiedtimecheckerinterface.h
index a0e79b0701..b48c38869e 100644
--- a/src/libs/clangsupport/modifiedtimecheckerinterface.h
+++ b/src/libs/clangsupport/modifiedtimecheckerinterface.h
@@ -38,6 +38,7 @@ public:
ModifiedTimeCheckerInterface &operator=(const ModifiedTimeCheckerInterface &) = delete;
virtual bool isUpToDate(const SourceEntries &sourceEntries) const = 0;
+ virtual void pathsChanged(const FilePathIds &filePathIds) = 0;
protected:
~ModifiedTimeCheckerInterface() = default;
diff --git a/src/libs/clangsupport/refactoringdatabaseinitializer.h b/src/libs/clangsupport/refactoringdatabaseinitializer.h
index a7058d3204..6042264a5d 100644
--- a/src/libs/clangsupport/refactoringdatabaseinitializer.h
+++ b/src/libs/clangsupport/refactoringdatabaseinitializer.h
@@ -144,11 +144,11 @@ public:
table.setName("projectPartsFiles");
const Sqlite::Column &projectPartIdColumn = table.addColumn("projectPartId", Sqlite::ColumnType::Integer);
const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
- table.addColumn("sourceType", Sqlite::ColumnType::Integer);
+ const Sqlite::Column &sourceType = table.addColumn("sourceType", Sqlite::ColumnType::Integer);
table.addColumn("pchCreationTimeStamp", Sqlite::ColumnType::Integer);
table.addColumn("hasMissingIncludes", Sqlite::ColumnType::Integer);
table.addUniqueIndex({sourceIdColumn, projectPartIdColumn});
- table.addIndex({projectPartIdColumn});
+ table.addIndex({projectPartIdColumn, sourceType});
table.initialize(database);
}
diff --git a/src/libs/clangsupport/set_algorithm.h b/src/libs/clangsupport/set_algorithm.h
new file mode 100644
index 0000000000..39bd3a2055
--- /dev/null
+++ b/src/libs/clangsupport/set_algorithm.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 <algorithm>
+
+namespace ClangBackEnd {
+
+template<class Callable>
+class function_output_iterator
+{
+public:
+ typedef std::output_iterator_tag iterator_category;
+ typedef void value_type;
+ typedef void difference_type;
+ typedef void pointer;
+ typedef void reference;
+
+ explicit function_output_iterator() {}
+
+ explicit function_output_iterator(const Callable &callable)
+ : m_callable(&callable)
+ {}
+
+ function_output_iterator &operator=(const function_output_iterator &iterator)
+ {
+ m_callable = iterator.m_callable;
+
+ return *this;
+ }
+
+ struct helper
+ {
+ helper(const Callable *callable)
+ : m_callable(callable)
+ {}
+ template<class T>
+ helper &operator=(T &&value)
+ {
+ (*m_callable)(std::forward<T>(value));
+ return *this;
+ }
+ const Callable *m_callable;
+ };
+
+ helper operator*() { return helper(m_callable); }
+ function_output_iterator &operator++() { return *this; }
+ function_output_iterator &operator++(int) { return *this; }
+
+private:
+ const Callable *m_callable;
+};
+
+template<typename Callable>
+function_output_iterator<Callable> make_iterator(const Callable &callable)
+{
+ return function_output_iterator<Callable>(callable);
+}
+
+template<class InputIt1, class InputIt2, class Callable, class Compare>
+bool set_intersection_compare(
+ InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable call, Compare comp)
+{
+ while (first1 != last1 && first2 != last2) {
+ if (comp(*first1, *first2)) {
+ ++first1;
+ } else {
+ if (!comp(*first2, *first1)) {
+ if (call(*first2, *first1++))
+ return false;
+ }
+ ++first2;
+ }
+ }
+
+ return true;
+}
+} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/sourceentry.h b/src/libs/clangsupport/sourceentry.h
index c593f1fcd3..5e8769d14f 100644
--- a/src/libs/clangsupport/sourceentry.h
+++ b/src/libs/clangsupport/sourceentry.h
@@ -131,6 +131,10 @@ public:
return first.sourceId < second.sourceId;
}
+ friend bool operator<(SourceEntry first, FilePathId second) { return first.sourceId < second; }
+
+ friend bool operator<(FilePathId first, SourceEntry second) { return first < second.sourceId; }
+
friend bool operator==(SourceEntry first, SourceEntry second)
{
return first.sourceId == second.sourceId && first.sourceType == second.sourceType
diff --git a/src/libs/languageserverprotocol/icontent.h b/src/libs/languageserverprotocol/icontent.h
index af14604739..1b57165b2e 100644
--- a/src/libs/languageserverprotocol/icontent.h
+++ b/src/libs/languageserverprotocol/icontent.h
@@ -92,7 +92,7 @@ using ResponseHandler = std::function<void(const QByteArray &, QTextCodec *)>;
using ResponseHandlers = std::function<void(MessageId, const QByteArray &, QTextCodec *)>;
using MethodHandler = std::function<void(const QString, MessageId, const IContent *)>;
-inline LANGUAGESERVERPROTOCOL_EXPORT uint qHash(const LanguageServerProtocol::MessageId &id)
+inline uint qHash(const LanguageServerProtocol::MessageId &id)
{
if (Utils::holds_alternative<int>(id))
return QT_PREPEND_NAMESPACE(qHash(Utils::get<int>(id)));
@@ -102,8 +102,7 @@ inline LANGUAGESERVERPROTOCOL_EXPORT uint qHash(const LanguageServerProtocol::Me
}
template <typename Error>
-inline LANGUAGESERVERPROTOCOL_EXPORT QDebug operator<<(QDebug stream,
- const LanguageServerProtocol::MessageId &id)
+inline QDebug operator<<(QDebug stream, const LanguageServerProtocol::MessageId &id)
{
if (Utils::holds_alternative<int>(id))
stream << Utils::get<int>(id);
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index deb95ea1d3..e5243830cd 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -1676,7 +1676,7 @@ bool Check::visit(CallExpression *ast)
if (!whiteListedFunction && !isMathFunction && !isDateFunction && !isDirectInConnectionsScope)
addMessage(ErrFunctionsNotSupportedInQmlUi, location);
- static const QStringList globalFunctions = {"String", "Boolean", "Date", "Number", "Object", "QT_TR_NOOP", "QT_TRANSLATE_NOOP", "QT_TRID_NOOP"};
+ static const QStringList globalFunctions = {"String", "Boolean", "Date", "Number", "Object", "Array", "QT_TR_NOOP", "QT_TRANSLATE_NOOP", "QT_TRID_NOOP"};
if (!name.isEmpty() && name.at(0).isUpper() && !globalFunctions.contains(name)) {
addMessage(WarnExpectedNewWithUppercaseFunction, location);
diff --git a/src/libs/utils/smallstringview.h b/src/libs/utils/smallstringview.h
index 6052ff8777..911ba2eafd 100644
--- a/src/libs/utils/smallstringview.h
+++ b/src/libs/utils/smallstringview.h
@@ -179,6 +179,10 @@ public:
return m_pointer[0] == characterToSearch;
}
+ char back() const { return m_pointer[m_size - 1]; }
+
+ char operator[](std::size_t index) { return m_pointer[index]; }
+
private:
const char *m_pointer = "";
size_type m_size = 0;