forked from qt-creator/qt-creator
Clang: Add file cache
The database is using file path integer ids to handle file paths because otherwise we would save many redundant data. This patch is improving it further with the introduction of a database based file path cache. The entries are now divided in a directory path and file name. This is quite handy for directory based file watching. Change-Id: I03f2e388e43f3d521d6bf8e39dfb95eb2309dc73 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
@@ -33,8 +33,15 @@
|
||||
#include <coreplugin/find/searchresultwindow.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <refactoringdatabaseinitializer.h>
|
||||
#include <filepathcaching.h>
|
||||
|
||||
#include <sqlitedatabase.h>
|
||||
|
||||
#include <utils/hostosinfo.h>
|
||||
|
||||
#include <QDir>
|
||||
|
||||
namespace ClangRefactoring {
|
||||
|
||||
namespace {
|
||||
@@ -54,9 +61,12 @@ class ClangRefactoringPluginData
|
||||
{
|
||||
using ProjectUpdater = ClangPchManager::QtCreatorProjectUpdater<ClangPchManager::ProjectUpdater>;
|
||||
public:
|
||||
Sqlite::Database database{Utils::PathString{QDir::tempPath() + "/symbol.db"}};
|
||||
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database};
|
||||
ClangBackEnd::FilePathCaching filePathCache{database};
|
||||
RefactoringClient refactoringClient;
|
||||
ClangBackEnd::RefactoringConnectionClient connectionClient{&refactoringClient};
|
||||
RefactoringEngine engine{connectionClient.serverProxy(), refactoringClient};
|
||||
RefactoringEngine engine{connectionClient.serverProxy(), refactoringClient, filePathCache};
|
||||
QtCreatorSearch qtCreatorSearch{*Core::SearchResultWindow::instance()};
|
||||
QtCreatorClangQueryFindFilter qtCreatorfindFilter{connectionClient.serverProxy(),
|
||||
qtCreatorSearch,
|
||||
|
||||
@@ -40,14 +40,9 @@ public:
|
||||
{}
|
||||
Database &database;
|
||||
ReadStatement selectLocationsForSymbolLocation{
|
||||
"SELECT sourceId, line, column FROM locations WHERE symbolId = "
|
||||
" (SELECT symbolId FROM locations WHERE sourceId="
|
||||
" (SELECT sourceId FROM sources WHERE sourcePath =?)"
|
||||
" AND line=? AND column=?) "
|
||||
"SELECT directoryId, sourceId, line, column FROM locations JOIN sources USING(sourceId) WHERE symbolId = "
|
||||
" (SELECT symbolId FROM locations WHERE sourceId=? AND line=? AND column=?) "
|
||||
"ORDER BY sourceId, line, column",
|
||||
database}; // alternatively SELECT l2.symbolid, l2.sourceId, l2.line, l2.column FROM locations AS l2, sources, locations AS l1 ON sources.sourceId = l1.sourceId AND l2.symbolId=l1.symbolId WHERE sourcePath = ? AND l1.line=? AND l1.column=? ORDER BY l2.sourceId, l2.line, l2.column
|
||||
ReadStatement selectSourcePathForId{
|
||||
"SELECT sourceId, sourcePath FROM sources WHERE sourceId = ?",
|
||||
database};
|
||||
};
|
||||
|
||||
|
||||
@@ -28,8 +28,9 @@
|
||||
#include "clangqueryhighlighter.h"
|
||||
#include "clangqueryexamplehighlighter.h"
|
||||
|
||||
#include <refactoringconnectionclient.h>
|
||||
#include <clangrefactoringmessages.h>
|
||||
#include <filepathcachinginterface.h>
|
||||
#include <refactoringconnectionclient.h>
|
||||
|
||||
namespace ClangRefactoring {
|
||||
|
||||
@@ -43,8 +44,8 @@ void RefactoringClient::sourceLocationsForRenamingMessage(
|
||||
ClangBackEnd::SourceLocationsForRenamingMessage &&message)
|
||||
{
|
||||
m_localRenamingCallback(message.symbolName().toQString(),
|
||||
message.sourceLocations(),
|
||||
message.textDocumentRevision());
|
||||
message.sourceLocations(),
|
||||
message.textDocumentRevision());
|
||||
|
||||
m_refactoringEngine->setUsable(true);
|
||||
}
|
||||
@@ -122,45 +123,24 @@ void RefactoringClient::setRefactoringConnectionClient(
|
||||
m_connectionClient = connectionClient;
|
||||
}
|
||||
|
||||
std::unordered_map<uint, QString> RefactoringClient::convertFilePaths(
|
||||
const ClangBackEnd::FilePathDict &filePaths)
|
||||
{
|
||||
using Dict = std::unordered_map<uint, QString>;
|
||||
Dict qstringFilePaths;
|
||||
qstringFilePaths.reserve(filePaths.size());
|
||||
|
||||
auto convertFilePath = [] (const ClangBackEnd::FilePathDict::value_type &dictonaryEntry) {
|
||||
return std::make_pair(dictonaryEntry.first,
|
||||
dictonaryEntry.second.path().toQString());
|
||||
};
|
||||
|
||||
std::transform(filePaths.begin(),
|
||||
filePaths.end(),
|
||||
std::inserter(qstringFilePaths, qstringFilePaths.begin()),
|
||||
convertFilePath);
|
||||
|
||||
return qstringFilePaths;
|
||||
}
|
||||
|
||||
void RefactoringClient::addSearchResults(const ClangBackEnd::SourceRangesContainer &sourceRanges)
|
||||
{
|
||||
auto filePaths = convertFilePaths(sourceRanges.filePaths());
|
||||
|
||||
for (const auto &sourceRangeWithText : sourceRanges.sourceRangeWithTextContainers())
|
||||
addSearchResult(sourceRangeWithText, filePaths);
|
||||
addSearchResult(sourceRangeWithText);
|
||||
}
|
||||
|
||||
void RefactoringClient::addSearchResult(const ClangBackEnd::SourceRangeWithTextContainer &sourceRangeWithText,
|
||||
std::unordered_map<uint, QString> &filePaths)
|
||||
void RefactoringClient::addSearchResult(const ClangBackEnd::SourceRangeWithTextContainer &sourceRangeWithText)
|
||||
{
|
||||
m_searchHandle->addResult(filePaths[sourceRangeWithText.fileHash()],
|
||||
QString(sourceRangeWithText.text()),
|
||||
{{int(sourceRangeWithText.start().line()),
|
||||
int(sourceRangeWithText.start().column() - 1),
|
||||
int(sourceRangeWithText.start().offset())},
|
||||
{int(sourceRangeWithText.end().line()),
|
||||
int(sourceRangeWithText.end().column() - 1),
|
||||
int(sourceRangeWithText.end().offset())}});
|
||||
auto &filePathCache = m_refactoringEngine->filePathCache();
|
||||
|
||||
m_searchHandle->addResult(QString(filePathCache.filePath(sourceRangeWithText.filePathId()).path()),
|
||||
QString(sourceRangeWithText.text()),
|
||||
{{int(sourceRangeWithText.start().line()),
|
||||
int(sourceRangeWithText.start().column() - 1),
|
||||
int(sourceRangeWithText.start().offset())},
|
||||
{int(sourceRangeWithText.end().line()),
|
||||
int(sourceRangeWithText.end().column() - 1),
|
||||
int(sourceRangeWithText.end().offset())}});
|
||||
}
|
||||
|
||||
void RefactoringClient::setResultCounterAndSendSearchIsFinishedIfFinished()
|
||||
|
||||
@@ -66,9 +66,6 @@ public:
|
||||
|
||||
bool hasValidLocalRenamingCallback() const;
|
||||
|
||||
static std::unordered_map<uint, QString> convertFilePaths(
|
||||
const std::unordered_map<uint, ClangBackEnd::FilePath> &filePaths);
|
||||
|
||||
void setExpectedResultCount(uint count);
|
||||
uint expectedResultCount() const;
|
||||
uint resultCounter() const;
|
||||
@@ -76,8 +73,7 @@ public:
|
||||
void setRefactoringConnectionClient(ClangBackEnd::RefactoringConnectionClient *connectionClient);
|
||||
|
||||
unittest_public:
|
||||
void addSearchResult(const ClangBackEnd::SourceRangeWithTextContainer &sourceRange,
|
||||
std::unordered_map<uint, QString> &filePaths);
|
||||
void addSearchResult(const ClangBackEnd::SourceRangeWithTextContainer &sourceRange);
|
||||
|
||||
private:
|
||||
void addSearchResults(const ClangBackEnd::SourceRangesContainer &sourceRanges);
|
||||
|
||||
@@ -46,9 +46,11 @@ namespace ClangRefactoring {
|
||||
using ClangBackEnd::RequestSourceLocationsForRenamingMessage;
|
||||
|
||||
RefactoringEngine::RefactoringEngine(ClangBackEnd::RefactoringServerInterface &server,
|
||||
ClangBackEnd::RefactoringClientInterface &client)
|
||||
: server(server),
|
||||
client(client)
|
||||
ClangBackEnd::RefactoringClientInterface &client,
|
||||
ClangBackEnd::FilePathCachingInterface &filePathCache)
|
||||
: m_server(server),
|
||||
m_client(client),
|
||||
m_filePathCache(filePathCache)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -60,7 +62,7 @@ void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data,
|
||||
|
||||
setUsable(false);
|
||||
|
||||
client.setLocalRenamingCallback(std::move(renameSymbolsCallback));
|
||||
m_client.setLocalRenamingCallback(std::move(renameSymbolsCallback));
|
||||
|
||||
QString filePath = data.filePath().toString();
|
||||
QTextCursor textCursor = data.cursor();
|
||||
@@ -79,7 +81,7 @@ void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data,
|
||||
textCursor.document()->revision());
|
||||
|
||||
|
||||
server.requestSourceLocationsForRenamingMessage(std::move(message));
|
||||
m_server.requestSourceLocationsForRenamingMessage(std::move(message));
|
||||
}
|
||||
|
||||
void RefactoringEngine::startGlobalRenaming(const CppTools::CursorInEditor &)
|
||||
@@ -89,12 +91,12 @@ void RefactoringEngine::startGlobalRenaming(const CppTools::CursorInEditor &)
|
||||
|
||||
bool RefactoringEngine::isUsable() const
|
||||
{
|
||||
return server.isUsable();
|
||||
return m_server.isUsable();
|
||||
}
|
||||
|
||||
void RefactoringEngine::setUsable(bool isUsable)
|
||||
{
|
||||
server.setUsable(isUsable);
|
||||
m_server.setUsable(isUsable);
|
||||
}
|
||||
|
||||
} // namespace ClangRefactoring
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filepathcachingfwd.h>
|
||||
|
||||
#include <cpptools/refactoringengineinterface.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
@@ -37,8 +39,10 @@ namespace ClangRefactoring {
|
||||
class RefactoringEngine : public CppTools::RefactoringEngineInterface
|
||||
{
|
||||
public:
|
||||
RefactoringEngine(ClangBackEnd::RefactoringServerInterface &server,
|
||||
ClangBackEnd::RefactoringClientInterface &client);
|
||||
RefactoringEngine(ClangBackEnd::RefactoringServerInterface &m_server,
|
||||
ClangBackEnd::RefactoringClientInterface &m_client,
|
||||
ClangBackEnd::FilePathCachingInterface &filePathCache);
|
||||
|
||||
void startLocalRenaming(const CppTools::CursorInEditor &data,
|
||||
CppTools::ProjectPart *projectPart,
|
||||
RenameCallback &&renameSymbolsCallback) override;
|
||||
@@ -47,9 +51,15 @@ public:
|
||||
bool isUsable() const override;
|
||||
void setUsable(bool isUsable);
|
||||
|
||||
ClangBackEnd::FilePathCachingInterface &filePathCache()
|
||||
{
|
||||
return m_filePathCache;
|
||||
}
|
||||
|
||||
private:
|
||||
ClangBackEnd::RefactoringServerInterface &server;
|
||||
ClangBackEnd::RefactoringClientInterface &client;
|
||||
ClangBackEnd::RefactoringServerInterface &m_server;
|
||||
ClangBackEnd::RefactoringClientInterface &m_client;
|
||||
ClangBackEnd::FilePathCachingInterface &m_filePathCache;
|
||||
};
|
||||
|
||||
} // namespace ClangRefactoring
|
||||
|
||||
@@ -27,39 +27,26 @@
|
||||
|
||||
#include <utils/smallstring.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <filepathid.h>
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ClangRefactoring {
|
||||
|
||||
class SourceLocations
|
||||
struct SourceLocation
|
||||
{
|
||||
public:
|
||||
struct Location
|
||||
{
|
||||
Location(qint64 sourceId, qint64 line, qint64 column)
|
||||
: sourceId(sourceId), line(line), column(column)
|
||||
{}
|
||||
SourceLocation(ClangBackEnd::FilePathId filePathId, int line, int column)
|
||||
: filePathId(filePathId), line(line), column(column)
|
||||
{}
|
||||
SourceLocation(int directoryId, int sourceId, int line, int column)
|
||||
: filePathId{directoryId, sourceId}, line(line), column(column)
|
||||
{}
|
||||
|
||||
qint64 sourceId;
|
||||
qint64 line;
|
||||
qint64 column;
|
||||
};
|
||||
|
||||
struct Source
|
||||
{
|
||||
Source(qint64 sourceId, Utils::PathString &&sourcePath)
|
||||
: sourceId(sourceId), sourcePath(std::move(sourcePath))
|
||||
{}
|
||||
|
||||
qint64 sourceId;
|
||||
Utils::PathString sourcePath;
|
||||
};
|
||||
|
||||
std::vector<Location> locations;
|
||||
std::unordered_map<qint64, Utils::PathString> sources;
|
||||
ClangBackEnd::FilePathId filePathId;
|
||||
int line;
|
||||
int column;
|
||||
};
|
||||
|
||||
using SourceLocations = std::vector<SourceLocation>;
|
||||
|
||||
} // namespace ClangRefactoring
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <utils/smallstring.h>
|
||||
|
||||
#include <filepathid.h>
|
||||
#include <sourcelocations.h>
|
||||
|
||||
#include <algorithm>
|
||||
@@ -39,68 +40,20 @@ class SymbolQuery
|
||||
using ReadStatement = typename StatementFactory::ReadStatementType;
|
||||
|
||||
public:
|
||||
using Location = SourceLocations::Location;
|
||||
using Source = SourceLocations::Source;
|
||||
|
||||
SymbolQuery(StatementFactory &statementFactory)
|
||||
: m_statementFactory(statementFactory)
|
||||
{}
|
||||
|
||||
SourceLocations locationsAt(const Utils::PathString &filePath, uint line, uint utf8Column)
|
||||
SourceLocations locationsAt(ClangBackEnd::FilePathId filePathId, int line, int utf8Column)
|
||||
{
|
||||
ReadStatement &locationsStatement = m_statementFactory.selectLocationsForSymbolLocation;
|
||||
|
||||
const std::size_t reserveSize = 128;
|
||||
|
||||
auto locations = locationsStatement.template values<Location, 3>(
|
||||
reserveSize,
|
||||
filePath,
|
||||
line,
|
||||
utf8Column);
|
||||
|
||||
const std::vector<qint64> sourceIds = uniqueSourceIds(locations);
|
||||
|
||||
ReadStatement &sourcesStatement = m_statementFactory.selectSourcePathForId;
|
||||
|
||||
auto sources = sourcesStatement.template values<Source, 2>(
|
||||
reserveSize,
|
||||
sourceIds);
|
||||
|
||||
return {locations, sourcesToHashMap(sources)};
|
||||
}
|
||||
|
||||
static
|
||||
qint64 sourceId(const Location &location)
|
||||
{
|
||||
return location.sourceId;
|
||||
}
|
||||
|
||||
static
|
||||
std::vector<qint64> uniqueSourceIds(const std::vector<Location> &locations)
|
||||
{
|
||||
std::vector<qint64> ids;
|
||||
ids.reserve(locations.size());
|
||||
|
||||
std::transform(locations.begin(),
|
||||
locations.end(),
|
||||
std::back_inserter(ids),
|
||||
sourceId);
|
||||
|
||||
auto newEnd = std::unique(ids.begin(), ids.end());
|
||||
ids.erase(newEnd, ids.end());
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
static
|
||||
std::unordered_map<qint64, Utils::PathString> sourcesToHashMap(const std::vector<Source> &sources)
|
||||
{
|
||||
std::unordered_map<qint64, Utils::PathString> dictonary;
|
||||
|
||||
for (const Source &source : sources)
|
||||
dictonary.emplace(source.sourceId, std::move(source.sourcePath));
|
||||
|
||||
return dictonary;
|
||||
return locationsStatement.template values<SourceLocation, 4>(reserveSize,
|
||||
filePathId.fileNameId,
|
||||
line,
|
||||
utf8Column);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user