forked from qt-creator/qt-creator
CppIndexingSupport: Flatten class hierarchy
Don't make CppIndexingSupport a pure virtual class as there is only one subclass. Change-Id: I9f216a2f1f5d04f601d07b9507a4e9cf27ff7c46 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -10,7 +10,6 @@ add_qtc_plugin(CppEditor
|
|||||||
builtincursorinfo.cpp builtincursorinfo.h
|
builtincursorinfo.cpp builtincursorinfo.h
|
||||||
builtineditordocumentparser.cpp builtineditordocumentparser.h
|
builtineditordocumentparser.cpp builtineditordocumentparser.h
|
||||||
builtineditordocumentprocessor.cpp builtineditordocumentprocessor.h
|
builtineditordocumentprocessor.cpp builtineditordocumentprocessor.h
|
||||||
builtinindexingsupport.cpp builtinindexingsupport.h
|
|
||||||
clangdiagnosticconfig.cpp clangdiagnosticconfig.h
|
clangdiagnosticconfig.cpp clangdiagnosticconfig.h
|
||||||
clangdiagnosticconfigsmodel.cpp clangdiagnosticconfigsmodel.h
|
clangdiagnosticconfigsmodel.cpp clangdiagnosticconfigsmodel.h
|
||||||
clangdiagnosticconfigsselectionwidget.cpp clangdiagnosticconfigsselectionwidget.h
|
clangdiagnosticconfigsselectionwidget.cpp clangdiagnosticconfigsselectionwidget.h
|
||||||
|
@@ -1,361 +0,0 @@
|
|||||||
// Copyright (C) 2016 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#include "builtinindexingsupport.h"
|
|
||||||
|
|
||||||
#include "builtineditordocumentparser.h"
|
|
||||||
#include "cppchecksymbols.h"
|
|
||||||
#include "cppeditorconstants.h"
|
|
||||||
#include "cppmodelmanager.h"
|
|
||||||
#include "cppprojectfile.h"
|
|
||||||
#include "cppsourceprocessor.h"
|
|
||||||
#include "cpptoolsreuse.h"
|
|
||||||
#include "searchsymbols.h"
|
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
|
||||||
#include <coreplugin/find/searchresultwindow.h>
|
|
||||||
#include <coreplugin/progressmanager/progressmanager.h>
|
|
||||||
|
|
||||||
#include <cplusplus/LookupContext.h>
|
|
||||||
#include <utils/environment.h>
|
|
||||||
#include <utils/qtcassert.h>
|
|
||||||
#include <utils/runextensions.h>
|
|
||||||
#include <utils/stringutils.h>
|
|
||||||
#include <utils/temporarydirectory.h>
|
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QElapsedTimer>
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
#include <QRegularExpression>
|
|
||||||
|
|
||||||
using namespace Utils;
|
|
||||||
|
|
||||||
namespace CppEditor::Internal {
|
|
||||||
|
|
||||||
static Q_LOGGING_CATEGORY(indexerLog, "qtc.cppeditor.indexer", QtWarningMsg)
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class ParseParams
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ProjectExplorer::HeaderPaths headerPaths;
|
|
||||||
WorkingCopy workingCopy;
|
|
||||||
QSet<QString> sourceFiles;
|
|
||||||
int indexerFileSizeLimitInMb = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
class WriteTaskFileForDiagnostics
|
|
||||||
{
|
|
||||||
Q_DISABLE_COPY(WriteTaskFileForDiagnostics)
|
|
||||||
|
|
||||||
public:
|
|
||||||
WriteTaskFileForDiagnostics()
|
|
||||||
{
|
|
||||||
const QString fileName = Utils::TemporaryDirectory::masterDirectoryPath()
|
|
||||||
+ "/qtc_findErrorsIndexing.diagnostics."
|
|
||||||
+ QDateTime::currentDateTime().toString("yyMMdd_HHmm") + ".tasks";
|
|
||||||
|
|
||||||
m_file.setFileName(fileName);
|
|
||||||
Q_ASSERT(m_file.open(QIODevice::WriteOnly | QIODevice::Text));
|
|
||||||
m_out.setDevice(&m_file);
|
|
||||||
|
|
||||||
qDebug("FindErrorsIndexing: Task file for diagnostics is \"%s\".",
|
|
||||||
qPrintable(m_file.fileName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
~WriteTaskFileForDiagnostics()
|
|
||||||
{
|
|
||||||
qDebug("FindErrorsIndexing: %d diagnostic messages written to \"%s\".",
|
|
||||||
m_processedDiagnostics, qPrintable(m_file.fileName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void process(const CPlusPlus::Document::Ptr document)
|
|
||||||
{
|
|
||||||
using namespace CPlusPlus;
|
|
||||||
const QString fileName = document->filePath().toString();
|
|
||||||
|
|
||||||
const QList<Document::DiagnosticMessage> messages = document->diagnosticMessages();
|
|
||||||
for (const Document::DiagnosticMessage &message : messages) {
|
|
||||||
++m_processedDiagnostics;
|
|
||||||
|
|
||||||
QString type;
|
|
||||||
switch (message.level()) {
|
|
||||||
case Document::DiagnosticMessage::Warning:
|
|
||||||
type = QLatin1String("warn"); break;
|
|
||||||
case Document::DiagnosticMessage::Error:
|
|
||||||
case Document::DiagnosticMessage::Fatal:
|
|
||||||
type = QLatin1String("err"); break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// format: file\tline\ttype\tdescription
|
|
||||||
m_out << fileName << "\t"
|
|
||||||
<< message.line() << "\t"
|
|
||||||
<< type << "\t"
|
|
||||||
<< message.text() << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
QFile m_file;
|
|
||||||
QTextStream m_out;
|
|
||||||
int m_processedDiagnostics = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
void classifyFiles(const QSet<QString> &files, QStringList *headers, QStringList *sources)
|
|
||||||
{
|
|
||||||
for (const QString &file : files) {
|
|
||||||
if (ProjectFile::isSource(ProjectFile::classify(file)))
|
|
||||||
sources->append(file);
|
|
||||||
else
|
|
||||||
headers->append(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void indexFindErrors(QFutureInterface<void> &indexingFuture,
|
|
||||||
const ParseParams params)
|
|
||||||
{
|
|
||||||
QStringList sources, headers;
|
|
||||||
classifyFiles(params.sourceFiles, &headers, &sources);
|
|
||||||
sources.sort();
|
|
||||||
headers.sort();
|
|
||||||
QStringList files = sources + headers;
|
|
||||||
|
|
||||||
WriteTaskFileForDiagnostics taskFileWriter;
|
|
||||||
QElapsedTimer timer;
|
|
||||||
timer.start();
|
|
||||||
|
|
||||||
for (int i = 0, end = files.size(); i < end ; ++i) {
|
|
||||||
if (indexingFuture.isCanceled())
|
|
||||||
break;
|
|
||||||
|
|
||||||
const QString file = files.at(i);
|
|
||||||
qDebug("FindErrorsIndexing: \"%s\"", qPrintable(file));
|
|
||||||
|
|
||||||
// Parse the file as precisely as possible
|
|
||||||
BuiltinEditorDocumentParser parser(FilePath::fromString(file));
|
|
||||||
parser.setReleaseSourceAndAST(false);
|
|
||||||
parser.update({CppModelManager::instance()->workingCopy(), nullptr,
|
|
||||||
Utils::Language::Cxx, false});
|
|
||||||
CPlusPlus::Document::Ptr document = parser.document();
|
|
||||||
QTC_ASSERT(document, return);
|
|
||||||
|
|
||||||
// Write diagnostic messages
|
|
||||||
taskFileWriter.process(document);
|
|
||||||
|
|
||||||
// Look up symbols
|
|
||||||
CPlusPlus::LookupContext context(document, parser.snapshot());
|
|
||||||
CheckSymbols::go(document, context, QList<CheckSymbols::Result>()).waitForFinished();
|
|
||||||
|
|
||||||
document->releaseSourceAndAST();
|
|
||||||
|
|
||||||
indexingFuture.setProgressValue(i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString elapsedTime = Utils::formatElapsedTime(timer.elapsed());
|
|
||||||
qDebug("FindErrorsIndexing: %s", qPrintable(elapsedTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
void index(QFutureInterface<void> &indexingFuture,
|
|
||||||
const ParseParams params)
|
|
||||||
{
|
|
||||||
QScopedPointer<CppSourceProcessor> sourceProcessor(CppModelManager::createSourceProcessor());
|
|
||||||
sourceProcessor->setFileSizeLimitInMb(params.indexerFileSizeLimitInMb);
|
|
||||||
sourceProcessor->setHeaderPaths(params.headerPaths);
|
|
||||||
sourceProcessor->setWorkingCopy(params.workingCopy);
|
|
||||||
|
|
||||||
QStringList sources;
|
|
||||||
QStringList headers;
|
|
||||||
classifyFiles(params.sourceFiles, &headers, &sources);
|
|
||||||
|
|
||||||
for (const QString &file : std::as_const(params.sourceFiles))
|
|
||||||
sourceProcessor->removeFromCache(FilePath::fromString(file));
|
|
||||||
|
|
||||||
const int sourceCount = sources.size();
|
|
||||||
QStringList files = sources + headers;
|
|
||||||
|
|
||||||
sourceProcessor->setTodo(Utils::toSet(files));
|
|
||||||
|
|
||||||
const FilePath &conf = CppModelManager::configurationFileName();
|
|
||||||
bool processingHeaders = false;
|
|
||||||
|
|
||||||
CppModelManager *cmm = CppModelManager::instance();
|
|
||||||
const ProjectExplorer::HeaderPaths fallbackHeaderPaths = cmm->headerPaths();
|
|
||||||
const CPlusPlus::LanguageFeatures defaultFeatures =
|
|
||||||
CPlusPlus::LanguageFeatures::defaultFeatures();
|
|
||||||
|
|
||||||
qCDebug(indexerLog) << "About to index" << files.size() << "files.";
|
|
||||||
for (int i = 0; i < files.size(); ++i) {
|
|
||||||
if (indexingFuture.isCanceled())
|
|
||||||
break;
|
|
||||||
|
|
||||||
const QString fileName = files.at(i);
|
|
||||||
const QList<ProjectPart::ConstPtr> parts = cmm->projectPart(fileName);
|
|
||||||
const CPlusPlus::LanguageFeatures languageFeatures = parts.isEmpty()
|
|
||||||
? defaultFeatures
|
|
||||||
: parts.first()->languageFeatures;
|
|
||||||
sourceProcessor->setLanguageFeatures(languageFeatures);
|
|
||||||
|
|
||||||
const bool isSourceFile = i < sourceCount;
|
|
||||||
if (isSourceFile) {
|
|
||||||
sourceProcessor->run(conf);
|
|
||||||
} else if (!processingHeaders) {
|
|
||||||
sourceProcessor->run(conf);
|
|
||||||
|
|
||||||
processingHeaders = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
qCDebug(indexerLog) << " Indexing" << i + 1 << "of" << files.size() << ":" << fileName;
|
|
||||||
ProjectExplorer::HeaderPaths headerPaths = parts.isEmpty()
|
|
||||||
? fallbackHeaderPaths
|
|
||||||
: parts.first()->headerPaths;
|
|
||||||
sourceProcessor->setHeaderPaths(headerPaths);
|
|
||||||
sourceProcessor->run(FilePath::fromString(fileName));
|
|
||||||
|
|
||||||
indexingFuture.setProgressValue(files.size() - sourceProcessor->todo().size());
|
|
||||||
|
|
||||||
if (isSourceFile)
|
|
||||||
sourceProcessor->resetEnvironment();
|
|
||||||
}
|
|
||||||
qCDebug(indexerLog) << "Indexing finished.";
|
|
||||||
}
|
|
||||||
|
|
||||||
void parse(QFutureInterface<void> &indexingFuture, const ParseParams params)
|
|
||||||
{
|
|
||||||
const QSet<QString> &files = params.sourceFiles;
|
|
||||||
if (files.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
indexingFuture.setProgressRange(0, files.size());
|
|
||||||
|
|
||||||
if (BuiltinIndexingSupport::isFindErrorsIndexingActive())
|
|
||||||
indexFindErrors(indexingFuture, params);
|
|
||||||
else
|
|
||||||
index(indexingFuture, params);
|
|
||||||
|
|
||||||
indexingFuture.setProgressValue(files.size());
|
|
||||||
CppModelManager::instance()->finishedRefreshingSourceFiles(files);
|
|
||||||
}
|
|
||||||
|
|
||||||
class BuiltinSymbolSearcher: public SymbolSearcher
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BuiltinSymbolSearcher(const CPlusPlus::Snapshot &snapshot,
|
|
||||||
const Parameters ¶meters, const QSet<QString> &fileNames)
|
|
||||||
: m_snapshot(snapshot)
|
|
||||||
, m_parameters(parameters)
|
|
||||||
, m_fileNames(fileNames)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~BuiltinSymbolSearcher() override = default;
|
|
||||||
|
|
||||||
void runSearch(QFutureInterface<Core::SearchResultItem> &future) override
|
|
||||||
{
|
|
||||||
future.setProgressRange(0, m_snapshot.size());
|
|
||||||
future.setProgressValue(0);
|
|
||||||
int progress = 0;
|
|
||||||
|
|
||||||
SearchSymbols search;
|
|
||||||
search.setSymbolsToSearchFor(m_parameters.types);
|
|
||||||
CPlusPlus::Snapshot::const_iterator it = m_snapshot.begin();
|
|
||||||
|
|
||||||
QString findString = (m_parameters.flags & Core::FindRegularExpression
|
|
||||||
? m_parameters.text : QRegularExpression::escape(m_parameters.text));
|
|
||||||
if (m_parameters.flags & Core::FindWholeWords)
|
|
||||||
findString = QString::fromLatin1("\\b%1\\b").arg(findString);
|
|
||||||
QRegularExpression matcher(findString, (m_parameters.flags & Core::FindCaseSensitively
|
|
||||||
? QRegularExpression::NoPatternOption
|
|
||||||
: QRegularExpression::CaseInsensitiveOption));
|
|
||||||
matcher.optimize();
|
|
||||||
while (it != m_snapshot.end()) {
|
|
||||||
if (future.isPaused())
|
|
||||||
future.waitForResume();
|
|
||||||
if (future.isCanceled())
|
|
||||||
break;
|
|
||||||
if (m_fileNames.isEmpty() || m_fileNames.contains(it.value()->filePath().path())) {
|
|
||||||
QVector<Core::SearchResultItem> resultItems;
|
|
||||||
auto filter = [&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult {
|
|
||||||
if (matcher.match(info->symbolName()).hasMatch()) {
|
|
||||||
QString text = info->symbolName();
|
|
||||||
QString scope = info->symbolScope();
|
|
||||||
if (info->type() == IndexItem::Function) {
|
|
||||||
QString name;
|
|
||||||
info->unqualifiedNameAndScope(info->symbolName(), &name, &scope);
|
|
||||||
text = name + info->symbolType();
|
|
||||||
} else if (info->type() == IndexItem::Declaration){
|
|
||||||
text = info->representDeclaration();
|
|
||||||
}
|
|
||||||
|
|
||||||
Core::SearchResultItem item;
|
|
||||||
item.setPath(scope.split(QLatin1String("::"), Qt::SkipEmptyParts));
|
|
||||||
item.setLineText(text);
|
|
||||||
item.setIcon(info->icon());
|
|
||||||
item.setUserData(QVariant::fromValue(info));
|
|
||||||
resultItems << item;
|
|
||||||
}
|
|
||||||
|
|
||||||
return IndexItem::Recurse;
|
|
||||||
};
|
|
||||||
search(it.value())->visitAllChildren(filter);
|
|
||||||
if (!resultItems.isEmpty())
|
|
||||||
future.reportResults(resultItems);
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
++progress;
|
|
||||||
future.setProgressValue(progress);
|
|
||||||
}
|
|
||||||
if (future.isPaused())
|
|
||||||
future.waitForResume();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const CPlusPlus::Snapshot m_snapshot;
|
|
||||||
const Parameters m_parameters;
|
|
||||||
const QSet<QString> m_fileNames;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
BuiltinIndexingSupport::BuiltinIndexingSupport()
|
|
||||||
{
|
|
||||||
m_synchronizer.setCancelOnWait(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
BuiltinIndexingSupport::~BuiltinIndexingSupport() = default;
|
|
||||||
|
|
||||||
QFuture<void> BuiltinIndexingSupport::refreshSourceFiles(
|
|
||||||
const QSet<QString> &sourceFiles, CppModelManager::ProgressNotificationMode mode)
|
|
||||||
{
|
|
||||||
CppModelManager *mgr = CppModelManager::instance();
|
|
||||||
|
|
||||||
ParseParams params;
|
|
||||||
params.indexerFileSizeLimitInMb = indexerFileSizeLimitInMb();
|
|
||||||
params.headerPaths = mgr->headerPaths();
|
|
||||||
params.workingCopy = mgr->workingCopy();
|
|
||||||
params.sourceFiles = sourceFiles;
|
|
||||||
|
|
||||||
QFuture<void> result = Utils::runAsync(mgr->sharedThreadPool(), parse, params);
|
|
||||||
m_synchronizer.addFuture(result);
|
|
||||||
|
|
||||||
if (mode == CppModelManager::ForcedProgressNotification || sourceFiles.count() > 1) {
|
|
||||||
Core::ProgressManager::addTask(result, QCoreApplication::translate("CppEditor::Internal::BuiltinIndexingSupport", "Parsing C/C++ Files"),
|
|
||||||
CppEditor::Constants::TASK_INDEX);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
SymbolSearcher *BuiltinIndexingSupport::createSymbolSearcher(
|
|
||||||
const SymbolSearcher::Parameters ¶meters, const QSet<QString> &fileNames)
|
|
||||||
{
|
|
||||||
return new BuiltinSymbolSearcher(CppModelManager::instance()->snapshot(), parameters, fileNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BuiltinIndexingSupport::isFindErrorsIndexingActive()
|
|
||||||
{
|
|
||||||
return Utils::qtcEnvironmentVariable("QTC_FIND_ERRORS_INDEXING") == "1";
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace CppEditor::Internal
|
|
@@ -1,30 +0,0 @@
|
|||||||
// Copyright (C) 2016 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "cppindexingsupport.h"
|
|
||||||
#include "cppmodelmanager.h"
|
|
||||||
|
|
||||||
#include <utils/futuresynchronizer.h>
|
|
||||||
|
|
||||||
namespace CppEditor::Internal {
|
|
||||||
|
|
||||||
class BuiltinIndexingSupport: public CppIndexingSupport {
|
|
||||||
public:
|
|
||||||
BuiltinIndexingSupport();
|
|
||||||
~BuiltinIndexingSupport() override;
|
|
||||||
|
|
||||||
QFuture<void> refreshSourceFiles(const QSet<QString> &sourceFiles,
|
|
||||||
CppModelManager::ProgressNotificationMode mode) override;
|
|
||||||
SymbolSearcher *createSymbolSearcher(const SymbolSearcher::Parameters ¶meters,
|
|
||||||
const QSet<QString> &fileNames) override;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static bool isFindErrorsIndexingActive();
|
|
||||||
|
|
||||||
private:
|
|
||||||
Utils::FutureSynchronizer m_synchronizer;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace CppEditor::Internal
|
|
@@ -39,8 +39,6 @@ QtcPlugin {
|
|||||||
"builtineditordocumentparser.h",
|
"builtineditordocumentparser.h",
|
||||||
"builtineditordocumentprocessor.cpp",
|
"builtineditordocumentprocessor.cpp",
|
||||||
"builtineditordocumentprocessor.h",
|
"builtineditordocumentprocessor.h",
|
||||||
"builtinindexingsupport.cpp",
|
|
||||||
"builtinindexingsupport.h",
|
|
||||||
"clangdiagnosticconfig.cpp",
|
"clangdiagnosticconfig.cpp",
|
||||||
"clangdiagnosticconfig.h",
|
"clangdiagnosticconfig.h",
|
||||||
"clangdiagnosticconfigsmodel.cpp",
|
"clangdiagnosticconfigsmodel.cpp",
|
||||||
|
@@ -3,9 +3,29 @@
|
|||||||
|
|
||||||
#include "cppindexingsupport.h"
|
#include "cppindexingsupport.h"
|
||||||
|
|
||||||
|
#include "builtineditordocumentparser.h"
|
||||||
|
#include "cppchecksymbols.h"
|
||||||
|
#include "cppeditorconstants.h"
|
||||||
|
#include "cppsourceprocessor.h"
|
||||||
|
#include "searchsymbols.h"
|
||||||
|
|
||||||
|
#include <coreplugin/find/searchresultitem.h>
|
||||||
|
#include <coreplugin/progressmanager/progressmanager.h>
|
||||||
|
|
||||||
|
#include <cplusplus/LookupContext.h>
|
||||||
|
|
||||||
|
#include <utils/filepath.h>
|
||||||
|
#include <utils/runextensions.h>
|
||||||
|
#include <utils/stringutils.h>
|
||||||
|
#include <utils/temporarydirectory.h>
|
||||||
|
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
namespace CppEditor {
|
namespace CppEditor {
|
||||||
|
|
||||||
CppIndexingSupport::~CppIndexingSupport() = default;
|
static Q_LOGGING_CATEGORY(indexerLog, "qtc.cppeditor.indexer", QtWarningMsg)
|
||||||
|
|
||||||
SymbolSearcher::SymbolSearcher(QObject *parent)
|
SymbolSearcher::SymbolSearcher(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
@@ -14,4 +34,329 @@ SymbolSearcher::SymbolSearcher(QObject *parent)
|
|||||||
|
|
||||||
SymbolSearcher::~SymbolSearcher() = default;
|
SymbolSearcher::~SymbolSearcher() = default;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class ParseParams
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProjectExplorer::HeaderPaths headerPaths;
|
||||||
|
WorkingCopy workingCopy;
|
||||||
|
QSet<QString> sourceFiles;
|
||||||
|
int indexerFileSizeLimitInMb = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WriteTaskFileForDiagnostics
|
||||||
|
{
|
||||||
|
Q_DISABLE_COPY(WriteTaskFileForDiagnostics)
|
||||||
|
|
||||||
|
public:
|
||||||
|
WriteTaskFileForDiagnostics()
|
||||||
|
{
|
||||||
|
const QString fileName = Utils::TemporaryDirectory::masterDirectoryPath()
|
||||||
|
+ "/qtc_findErrorsIndexing.diagnostics."
|
||||||
|
+ QDateTime::currentDateTime().toString("yyMMdd_HHmm") + ".tasks";
|
||||||
|
|
||||||
|
m_file.setFileName(fileName);
|
||||||
|
Q_ASSERT(m_file.open(QIODevice::WriteOnly | QIODevice::Text));
|
||||||
|
m_out.setDevice(&m_file);
|
||||||
|
|
||||||
|
qDebug("FindErrorsIndexing: Task file for diagnostics is \"%s\".",
|
||||||
|
qPrintable(m_file.fileName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
~WriteTaskFileForDiagnostics()
|
||||||
|
{
|
||||||
|
qDebug("FindErrorsIndexing: %d diagnostic messages written to \"%s\".",
|
||||||
|
m_processedDiagnostics, qPrintable(m_file.fileName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void process(const CPlusPlus::Document::Ptr document)
|
||||||
|
{
|
||||||
|
using namespace CPlusPlus;
|
||||||
|
const QString fileName = document->filePath().toString();
|
||||||
|
|
||||||
|
const QList<Document::DiagnosticMessage> messages = document->diagnosticMessages();
|
||||||
|
for (const Document::DiagnosticMessage &message : messages) {
|
||||||
|
++m_processedDiagnostics;
|
||||||
|
|
||||||
|
QString type;
|
||||||
|
switch (message.level()) {
|
||||||
|
case Document::DiagnosticMessage::Warning:
|
||||||
|
type = QLatin1String("warn"); break;
|
||||||
|
case Document::DiagnosticMessage::Error:
|
||||||
|
case Document::DiagnosticMessage::Fatal:
|
||||||
|
type = QLatin1String("err"); break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// format: file\tline\ttype\tdescription
|
||||||
|
m_out << fileName << "\t"
|
||||||
|
<< message.line() << "\t"
|
||||||
|
<< type << "\t"
|
||||||
|
<< message.text() << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QFile m_file;
|
||||||
|
QTextStream m_out;
|
||||||
|
int m_processedDiagnostics = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void classifyFiles(const QSet<QString> &files, QStringList *headers, QStringList *sources)
|
||||||
|
{
|
||||||
|
for (const QString &file : files) {
|
||||||
|
if (ProjectFile::isSource(ProjectFile::classify(file)))
|
||||||
|
sources->append(file);
|
||||||
|
else
|
||||||
|
headers->append(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void indexFindErrors(QFutureInterface<void> &indexingFuture,
|
||||||
|
const ParseParams params)
|
||||||
|
{
|
||||||
|
QStringList sources, headers;
|
||||||
|
classifyFiles(params.sourceFiles, &headers, &sources);
|
||||||
|
sources.sort();
|
||||||
|
headers.sort();
|
||||||
|
QStringList files = sources + headers;
|
||||||
|
|
||||||
|
WriteTaskFileForDiagnostics taskFileWriter;
|
||||||
|
QElapsedTimer timer;
|
||||||
|
timer.start();
|
||||||
|
|
||||||
|
for (int i = 0, end = files.size(); i < end ; ++i) {
|
||||||
|
if (indexingFuture.isCanceled())
|
||||||
|
break;
|
||||||
|
|
||||||
|
const QString file = files.at(i);
|
||||||
|
qDebug("FindErrorsIndexing: \"%s\"", qPrintable(file));
|
||||||
|
|
||||||
|
// Parse the file as precisely as possible
|
||||||
|
BuiltinEditorDocumentParser parser(FilePath::fromString(file));
|
||||||
|
parser.setReleaseSourceAndAST(false);
|
||||||
|
parser.update({CppModelManager::instance()->workingCopy(), nullptr,
|
||||||
|
Utils::Language::Cxx, false});
|
||||||
|
CPlusPlus::Document::Ptr document = parser.document();
|
||||||
|
QTC_ASSERT(document, return);
|
||||||
|
|
||||||
|
// Write diagnostic messages
|
||||||
|
taskFileWriter.process(document);
|
||||||
|
|
||||||
|
// Look up symbols
|
||||||
|
CPlusPlus::LookupContext context(document, parser.snapshot());
|
||||||
|
CheckSymbols::go(document, context, QList<CheckSymbols::Result>()).waitForFinished();
|
||||||
|
|
||||||
|
document->releaseSourceAndAST();
|
||||||
|
|
||||||
|
indexingFuture.setProgressValue(i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString elapsedTime = Utils::formatElapsedTime(timer.elapsed());
|
||||||
|
qDebug("FindErrorsIndexing: %s", qPrintable(elapsedTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
void index(QFutureInterface<void> &indexingFuture,
|
||||||
|
const ParseParams params)
|
||||||
|
{
|
||||||
|
QScopedPointer<Internal::CppSourceProcessor> sourceProcessor(CppModelManager::createSourceProcessor());
|
||||||
|
sourceProcessor->setFileSizeLimitInMb(params.indexerFileSizeLimitInMb);
|
||||||
|
sourceProcessor->setHeaderPaths(params.headerPaths);
|
||||||
|
sourceProcessor->setWorkingCopy(params.workingCopy);
|
||||||
|
|
||||||
|
QStringList sources;
|
||||||
|
QStringList headers;
|
||||||
|
classifyFiles(params.sourceFiles, &headers, &sources);
|
||||||
|
|
||||||
|
for (const QString &file : std::as_const(params.sourceFiles))
|
||||||
|
sourceProcessor->removeFromCache(FilePath::fromString(file));
|
||||||
|
|
||||||
|
const int sourceCount = sources.size();
|
||||||
|
QStringList files = sources + headers;
|
||||||
|
|
||||||
|
sourceProcessor->setTodo(Utils::toSet(files));
|
||||||
|
|
||||||
|
const FilePath &conf = CppModelManager::configurationFileName();
|
||||||
|
bool processingHeaders = false;
|
||||||
|
|
||||||
|
CppModelManager *cmm = CppModelManager::instance();
|
||||||
|
const ProjectExplorer::HeaderPaths fallbackHeaderPaths = cmm->headerPaths();
|
||||||
|
const CPlusPlus::LanguageFeatures defaultFeatures =
|
||||||
|
CPlusPlus::LanguageFeatures::defaultFeatures();
|
||||||
|
|
||||||
|
qCDebug(indexerLog) << "About to index" << files.size() << "files.";
|
||||||
|
for (int i = 0; i < files.size(); ++i) {
|
||||||
|
if (indexingFuture.isCanceled())
|
||||||
|
break;
|
||||||
|
|
||||||
|
const QString fileName = files.at(i);
|
||||||
|
const QList<ProjectPart::ConstPtr> parts = cmm->projectPart(fileName);
|
||||||
|
const CPlusPlus::LanguageFeatures languageFeatures = parts.isEmpty()
|
||||||
|
? defaultFeatures
|
||||||
|
: parts.first()->languageFeatures;
|
||||||
|
sourceProcessor->setLanguageFeatures(languageFeatures);
|
||||||
|
|
||||||
|
const bool isSourceFile = i < sourceCount;
|
||||||
|
if (isSourceFile) {
|
||||||
|
sourceProcessor->run(conf);
|
||||||
|
} else if (!processingHeaders) {
|
||||||
|
sourceProcessor->run(conf);
|
||||||
|
|
||||||
|
processingHeaders = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(indexerLog) << " Indexing" << i + 1 << "of" << files.size() << ":" << fileName;
|
||||||
|
ProjectExplorer::HeaderPaths headerPaths = parts.isEmpty()
|
||||||
|
? fallbackHeaderPaths
|
||||||
|
: parts.first()->headerPaths;
|
||||||
|
sourceProcessor->setHeaderPaths(headerPaths);
|
||||||
|
sourceProcessor->run(FilePath::fromString(fileName));
|
||||||
|
|
||||||
|
indexingFuture.setProgressValue(files.size() - sourceProcessor->todo().size());
|
||||||
|
|
||||||
|
if (isSourceFile)
|
||||||
|
sourceProcessor->resetEnvironment();
|
||||||
|
}
|
||||||
|
qCDebug(indexerLog) << "Indexing finished.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse(QFutureInterface<void> &indexingFuture, const ParseParams params)
|
||||||
|
{
|
||||||
|
const QSet<QString> &files = params.sourceFiles;
|
||||||
|
if (files.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
indexingFuture.setProgressRange(0, files.size());
|
||||||
|
|
||||||
|
if (CppIndexingSupport::isFindErrorsIndexingActive())
|
||||||
|
indexFindErrors(indexingFuture, params);
|
||||||
|
else
|
||||||
|
index(indexingFuture, params);
|
||||||
|
|
||||||
|
indexingFuture.setProgressValue(files.size());
|
||||||
|
CppModelManager::instance()->finishedRefreshingSourceFiles(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
|
class BuiltinSymbolSearcher: public SymbolSearcher
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BuiltinSymbolSearcher(const CPlusPlus::Snapshot &snapshot,
|
||||||
|
const Parameters ¶meters, const QSet<QString> &fileNames)
|
||||||
|
: m_snapshot(snapshot)
|
||||||
|
, m_parameters(parameters)
|
||||||
|
, m_fileNames(fileNames)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~BuiltinSymbolSearcher() override = default;
|
||||||
|
|
||||||
|
void runSearch(QFutureInterface<Core::SearchResultItem> &future) override
|
||||||
|
{
|
||||||
|
future.setProgressRange(0, m_snapshot.size());
|
||||||
|
future.setProgressValue(0);
|
||||||
|
int progress = 0;
|
||||||
|
|
||||||
|
SearchSymbols search;
|
||||||
|
search.setSymbolsToSearchFor(m_parameters.types);
|
||||||
|
CPlusPlus::Snapshot::const_iterator it = m_snapshot.begin();
|
||||||
|
|
||||||
|
QString findString = (m_parameters.flags & Core::FindRegularExpression
|
||||||
|
? m_parameters.text : QRegularExpression::escape(m_parameters.text));
|
||||||
|
if (m_parameters.flags & Core::FindWholeWords)
|
||||||
|
findString = QString::fromLatin1("\\b%1\\b").arg(findString);
|
||||||
|
QRegularExpression matcher(findString, (m_parameters.flags & Core::FindCaseSensitively
|
||||||
|
? QRegularExpression::NoPatternOption
|
||||||
|
: QRegularExpression::CaseInsensitiveOption));
|
||||||
|
matcher.optimize();
|
||||||
|
while (it != m_snapshot.end()) {
|
||||||
|
if (future.isPaused())
|
||||||
|
future.waitForResume();
|
||||||
|
if (future.isCanceled())
|
||||||
|
break;
|
||||||
|
if (m_fileNames.isEmpty() || m_fileNames.contains(it.value()->filePath().path())) {
|
||||||
|
QVector<Core::SearchResultItem> resultItems;
|
||||||
|
auto filter = [&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult {
|
||||||
|
if (matcher.match(info->symbolName()).hasMatch()) {
|
||||||
|
QString text = info->symbolName();
|
||||||
|
QString scope = info->symbolScope();
|
||||||
|
if (info->type() == IndexItem::Function) {
|
||||||
|
QString name;
|
||||||
|
info->unqualifiedNameAndScope(info->symbolName(), &name, &scope);
|
||||||
|
text = name + info->symbolType();
|
||||||
|
} else if (info->type() == IndexItem::Declaration){
|
||||||
|
text = info->representDeclaration();
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::SearchResultItem item;
|
||||||
|
item.setPath(scope.split(QLatin1String("::"), Qt::SkipEmptyParts));
|
||||||
|
item.setLineText(text);
|
||||||
|
item.setIcon(info->icon());
|
||||||
|
item.setUserData(QVariant::fromValue(info));
|
||||||
|
resultItems << item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IndexItem::Recurse;
|
||||||
|
};
|
||||||
|
search(it.value())->visitAllChildren(filter);
|
||||||
|
if (!resultItems.isEmpty())
|
||||||
|
future.reportResults(resultItems);
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
++progress;
|
||||||
|
future.setProgressValue(progress);
|
||||||
|
}
|
||||||
|
if (future.isPaused())
|
||||||
|
future.waitForResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CPlusPlus::Snapshot m_snapshot;
|
||||||
|
const Parameters m_parameters;
|
||||||
|
const QSet<QString> m_fileNames;
|
||||||
|
};
|
||||||
|
|
||||||
|
CppIndexingSupport::CppIndexingSupport()
|
||||||
|
{
|
||||||
|
m_synchronizer.setCancelOnWait(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
CppIndexingSupport::~CppIndexingSupport() = default;
|
||||||
|
|
||||||
|
bool CppIndexingSupport::isFindErrorsIndexingActive()
|
||||||
|
{
|
||||||
|
return Utils::qtcEnvironmentVariable("QTC_FIND_ERRORS_INDEXING") == "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
QFuture<void> CppIndexingSupport::refreshSourceFiles(const QSet<QString> &sourceFiles,
|
||||||
|
CppModelManager::ProgressNotificationMode mode)
|
||||||
|
{
|
||||||
|
CppModelManager *mgr = CppModelManager::instance();
|
||||||
|
|
||||||
|
ParseParams params;
|
||||||
|
params.indexerFileSizeLimitInMb = indexerFileSizeLimitInMb();
|
||||||
|
params.headerPaths = mgr->headerPaths();
|
||||||
|
params.workingCopy = mgr->workingCopy();
|
||||||
|
params.sourceFiles = sourceFiles;
|
||||||
|
|
||||||
|
QFuture<void> result = Utils::runAsync(mgr->sharedThreadPool(), parse, params);
|
||||||
|
m_synchronizer.addFuture(result);
|
||||||
|
|
||||||
|
if (mode == CppModelManager::ForcedProgressNotification || sourceFiles.count() > 1) {
|
||||||
|
Core::ProgressManager::addTask(result, QCoreApplication::translate("CppEditor::Internal::BuiltinIndexingSupport", "Parsing C/C++ Files"),
|
||||||
|
CppEditor::Constants::TASK_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolSearcher *CppIndexingSupport::createSymbolSearcher(
|
||||||
|
const SymbolSearcher::Parameters ¶meters, const QSet<QString> &fileNames)
|
||||||
|
{
|
||||||
|
return new BuiltinSymbolSearcher(CppModelManager::instance()->snapshot(), parameters, fileNames);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace CppEditor
|
} // namespace CppEditor
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include "cppmodelmanager.h"
|
#include "cppmodelmanager.h"
|
||||||
|
|
||||||
#include <coreplugin/find/textfindconstants.h>
|
#include <coreplugin/find/textfindconstants.h>
|
||||||
|
#include <utils/futuresynchronizer.h>
|
||||||
|
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
@@ -51,17 +52,20 @@ public:
|
|||||||
virtual void runSearch(QFutureInterface<Core::SearchResultItem> &future) = 0;
|
virtual void runSearch(QFutureInterface<Core::SearchResultItem> &future) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class CPPEDITOR_EXPORT CppIndexingSupport
|
class CPPEDITOR_EXPORT CppIndexingSupport
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~CppIndexingSupport() = 0;
|
CppIndexingSupport();
|
||||||
|
~CppIndexingSupport();
|
||||||
|
|
||||||
virtual QFuture<void> refreshSourceFiles(const QSet<QString> &sourceFiles,
|
static bool isFindErrorsIndexingActive();
|
||||||
CppModelManager::ProgressNotificationMode mode)
|
|
||||||
= 0;
|
QFuture<void> refreshSourceFiles(const QSet<QString> &sourceFiles,
|
||||||
virtual SymbolSearcher *createSymbolSearcher(const SymbolSearcher::Parameters ¶meters,
|
CppModelManager::ProgressNotificationMode mode);
|
||||||
const QSet<QString> &fileNames) = 0;
|
SymbolSearcher *createSymbolSearcher(const SymbolSearcher::Parameters ¶meters,
|
||||||
|
const QSet<QString> &fileNames);
|
||||||
|
private:
|
||||||
|
Utils::FutureSynchronizer m_synchronizer;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CppEditor
|
} // namespace CppEditor
|
||||||
|
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include "abstracteditorsupport.h"
|
#include "abstracteditorsupport.h"
|
||||||
#include "baseeditordocumentprocessor.h"
|
#include "baseeditordocumentprocessor.h"
|
||||||
#include "builtinindexingsupport.h"
|
|
||||||
#include "compileroptionsbuilder.h"
|
#include "compileroptionsbuilder.h"
|
||||||
#include "cppcodemodelinspectordumper.h"
|
#include "cppcodemodelinspectordumper.h"
|
||||||
#include "cppcodemodelsettings.h"
|
#include "cppcodemodelsettings.h"
|
||||||
@@ -975,7 +974,7 @@ CppModelManager::CppModelManager()
|
|||||||
qRegisterMetaType<QList<Document::DiagnosticMessage>>(
|
qRegisterMetaType<QList<Document::DiagnosticMessage>>(
|
||||||
"QList<CPlusPlus::Document::DiagnosticMessage>");
|
"QList<CPlusPlus::Document::DiagnosticMessage>");
|
||||||
|
|
||||||
d->m_internalIndexingSupport = new BuiltinIndexingSupport;
|
d->m_internalIndexingSupport = new CppIndexingSupport;
|
||||||
|
|
||||||
initCppTools();
|
initCppTools();
|
||||||
}
|
}
|
||||||
@@ -1696,7 +1695,7 @@ void CppModelManager::onActiveProjectChanged(ProjectExplorer::Project *project)
|
|||||||
|
|
||||||
void CppModelManager::onSourceFilesRefreshed() const
|
void CppModelManager::onSourceFilesRefreshed() const
|
||||||
{
|
{
|
||||||
if (BuiltinIndexingSupport::isFindErrorsIndexingActive()) {
|
if (CppIndexingSupport::isFindErrorsIndexingActive()) {
|
||||||
QTimer::singleShot(1, QCoreApplication::instance(), &QCoreApplication::quit);
|
QTimer::singleShot(1, QCoreApplication::instance(), &QCoreApplication::quit);
|
||||||
qDebug("FindErrorsIndexing: Done, requesting Qt Creator to quit.");
|
qDebug("FindErrorsIndexing: Done, requesting Qt Creator to quit.");
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "symbolsearcher_test.h"
|
#include "symbolsearcher_test.h"
|
||||||
|
|
||||||
#include "builtinindexingsupport.h"
|
#include "cppindexingsupport.h"
|
||||||
#include "cppmodelmanager.h"
|
#include "cppmodelmanager.h"
|
||||||
#include "cpptoolstestcase.h"
|
#include "cpptoolstestcase.h"
|
||||||
#include "searchsymbols.h"
|
#include "searchsymbols.h"
|
||||||
|
Reference in New Issue
Block a user