forked from qt-creator/qt-creator
ClangCodeModel: Add menu action to re-index files
... that depend on changed headers. When changing a header file the clangd code model is not updated for files that including it if they are not opened in editor. This is not to be done automatically, as it would be a performance hazard to rescan many files, for example when changing a widely used header. Add a menu action to trigger such re-indexing manually to solve the issue. Task-number: QTCREATORBUG-27387 Change-Id: Ia8033401f847627cee041b102f9ac6f3af3dd709 Reviewed-by: Volodymyr Zibarov <gogan419@gmail.com> Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -48,7 +48,10 @@
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QLabel>
|
||||
#include <QLoggingCategory>
|
||||
#include <QMenu>
|
||||
#include <QTextBlock>
|
||||
#include <QTimer>
|
||||
@@ -61,6 +64,41 @@ using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
namespace ClangCodeModel::Internal {
|
||||
namespace {
|
||||
class IndexFiles
|
||||
{
|
||||
public:
|
||||
QList<Utils::FilePath> files;
|
||||
QDateTime minLastModifiedTime;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static Q_LOGGING_CATEGORY(clangdIndexLog, "qtc.clangcodemodel.clangd.index", QtWarningMsg);
|
||||
|
||||
static QHash<QString, IndexFiles> collectIndexedFiles(const Utils::FilePath &indexFolder)
|
||||
{
|
||||
QHash<QString, IndexFiles> result;
|
||||
QDirIterator dirIt(indexFolder.toFSPathString(), QDir::Files);
|
||||
while (dirIt.hasNext()) {
|
||||
dirIt.next();
|
||||
FilePath path = FilePath::fromString(dirIt.filePath());
|
||||
if (path.suffix() != "idx")
|
||||
continue;
|
||||
|
||||
QString baseName = path.completeBaseName();
|
||||
const int dotPos = baseName.lastIndexOf('.');
|
||||
if (dotPos <= 0)
|
||||
continue;
|
||||
|
||||
baseName = baseName.left(dotPos);
|
||||
IndexFiles &indexFiles = result[baseName];
|
||||
indexFiles.files.push_back(path);
|
||||
QDateTime time = path.lastModified();
|
||||
if (indexFiles.minLastModifiedTime.isNull() || time < indexFiles.minLastModifiedTime)
|
||||
indexFiles.minLastModifiedTime = time;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Project *fallbackProject()
|
||||
{
|
||||
@@ -644,6 +682,73 @@ ClangdClient *ClangModelManagerSupport::clientWithProject(const Project *project
|
||||
return clients.empty() ? nullptr : qobject_cast<ClangdClient *>(clients.first());
|
||||
}
|
||||
|
||||
void ClangModelManagerSupport::updateStaleIndexEntries()
|
||||
{
|
||||
QHash<FilePath, QDateTime> lastModifiedCache;
|
||||
for (const Project * const project : ProjectManager::projects()) {
|
||||
const FilePath jsonDbDir = getJsonDbDir(project);
|
||||
if (jsonDbDir.isEmpty())
|
||||
continue;
|
||||
|
||||
const FilePath indexFolder = jsonDbDir / ".cache" / "clangd" / "index";
|
||||
if (!indexFolder.exists())
|
||||
continue;
|
||||
|
||||
const QHash<QString, IndexFiles> indexedFiles = collectIndexedFiles(indexFolder);
|
||||
bool restartCodeModel = false;
|
||||
const CPlusPlus::Snapshot snapshot = CppModelManager::snapshot();
|
||||
for (const CPlusPlus::Document::Ptr &document : snapshot) {
|
||||
const FilePath sourceFile = document->filePath();
|
||||
if (sourceFile.fileName() == "<configuration>")
|
||||
continue;
|
||||
|
||||
if (!project->isKnownFile(sourceFile)) {
|
||||
qCDebug(clangdIndexLog) << "Not in project:" << sourceFile.fileName();
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto indexFilesIt = indexedFiles.find(sourceFile.fileName());
|
||||
if (indexFilesIt == indexedFiles.end()) {
|
||||
qCDebug(clangdIndexLog) << "No index files for:" << sourceFile.fileName();
|
||||
continue;
|
||||
}
|
||||
|
||||
const QDateTime sourceIndexedTime = indexFilesIt->minLastModifiedTime;
|
||||
|
||||
bool rescan = false;
|
||||
QSet<FilePath> allIncludes = snapshot.allIncludesForDocument(sourceFile);
|
||||
for (const FilePath &includeFile : qAsConst(allIncludes)) {
|
||||
auto includeFileTimeIt = lastModifiedCache.find(includeFile);
|
||||
if (includeFileTimeIt == lastModifiedCache.end()) {
|
||||
includeFileTimeIt = lastModifiedCache.insert(includeFile,
|
||||
includeFile.lastModified());
|
||||
}
|
||||
if (sourceIndexedTime < includeFileTimeIt.value()) {
|
||||
qCDebug(clangdIndexLog) << "Rescan file:" << sourceFile.fileName()
|
||||
<< "indexed at" << sourceIndexedTime
|
||||
<< "changed include:" << includeFile.fileName()
|
||||
<< "last modified at" << includeFileTimeIt.value();
|
||||
rescan = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rescan) {
|
||||
for (const FilePath &indexFile : indexFilesIt->files)
|
||||
indexFile.removeFile();
|
||||
restartCodeModel = true;
|
||||
}
|
||||
}
|
||||
if (restartCodeModel) {
|
||||
if (ClangdClient * const client = clientForProject(project)) {
|
||||
const auto instance = dynamic_cast<ClangModelManagerSupport *>(
|
||||
CppModelManager::modelManagerSupport(CppModelManager::Backend::Best));
|
||||
QTC_ASSERT(instance, return);
|
||||
instance->scheduleClientRestart(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClangdClient *ClangModelManagerSupport::clientForFile(const FilePath &file)
|
||||
{
|
||||
return qobject_cast<ClangdClient *>(LanguageClientManager::clientForFilePath(file));
|
||||
|
||||
Reference in New Issue
Block a user