ClangCodeModel: Remove unneeded code

This was liblclang-specific.

Change-Id: I3fe8a8d2d49b1c7b92a54a90864e4ead7152e4ae
Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
Christian Kandeler
2023-01-13 15:54:51 +01:00
parent fc73324c50
commit 8257369b73
7 changed files with 21 additions and 771 deletions

View File

@@ -50,7 +50,6 @@ extend_qtc_plugin(ClangCodeModel
CONDITION WITH_TESTS CONDITION WITH_TESTS
SOURCES SOURCES
test/activationsequenceprocessortest.cpp test/activationsequenceprocessortest.h test/activationsequenceprocessortest.cpp test/activationsequenceprocessortest.h
test/clangbatchfileprocessor.cpp test/clangbatchfileprocessor.h
test/clangdtests.cpp test/clangdtests.h test/clangdtests.cpp test/clangdtests.h
test/clangfixittest.cpp test/clangfixittest.h test/clangfixittest.cpp test/clangfixittest.h
test/data/clangtestdata.qrc test/data/clangtestdata.qrc

View File

@@ -101,8 +101,6 @@ QtcPlugin {
files: [ files: [
"activationsequenceprocessortest.cpp", "activationsequenceprocessortest.cpp",
"activationsequenceprocessortest.h", "activationsequenceprocessortest.h",
"clangbatchfileprocessor.cpp",
"clangbatchfileprocessor.h",
"clangdtests.cpp", "clangdtests.cpp",
"clangdtests.h", "clangdtests.h",
"clangfixittest.cpp", "clangfixittest.cpp",

View File

@@ -10,7 +10,6 @@
#ifdef WITH_TESTS #ifdef WITH_TESTS
# include "test/activationsequenceprocessortest.h" # include "test/activationsequenceprocessortest.h"
# include "test/clangbatchfileprocessor.h"
# include "test/clangdtests.h" # include "test/clangdtests.h"
# include "test/clangfixittest.h" # include "test/clangfixittest.h"
#endif #endif
@@ -80,15 +79,8 @@ void ClangCodeModelPlugin::initialize()
{ {
TaskHub::addCategory(Constants::TASK_CATEGORY_DIAGNOSTICS, TaskHub::addCategory(Constants::TASK_CATEGORY_DIAGNOSTICS,
Tr::tr("Clang Code Model")); Tr::tr("Clang Code Model"));
connect(ProjectExplorerPlugin::instance(),
&ProjectExplorerPlugin::finishedInitialization,
this,
&ClangCodeModelPlugin::maybeHandleBatchFileAndExit);
CppEditor::CppModelManager::instance()->activateClangCodeModel( CppEditor::CppModelManager::instance()->activateClangCodeModel(
std::make_unique<ClangModelManagerSupport>()); std::make_unique<ClangModelManagerSupport>());
createCompilationDBAction(); createCompilationDBAction();
} }
@@ -166,18 +158,6 @@ void ClangCodeModelPlugin::createCompilationDBAction()
}); });
} }
// For e.g. creation of profile-guided optimization builds.
void ClangCodeModelPlugin::maybeHandleBatchFileAndExit() const
{
#ifdef WITH_TESTS
const QString batchFilePath = qtcEnvironmentVariable("QTC_CLANG_BATCH");
if (!batchFilePath.isEmpty() && QTC_GUARD(QFileInfo::exists(batchFilePath))) {
const bool runSucceeded = runClangBatchFile(batchFilePath);
QCoreApplication::exit(!runSucceeded);
}
#endif
}
#ifdef WITH_TESTS #ifdef WITH_TESTS
QVector<QObject *> ClangCodeModelPlugin::createTestObjects() const QVector<QObject *> ClangCodeModelPlugin::createTestObjects() const
{ {

View File

@@ -24,8 +24,6 @@ public:
void initialize() override; void initialize() override;
private: private:
void maybeHandleBatchFileAndExit() const;
void generateCompilationDB(); void generateCompilationDB();
void createCompilationDBAction(); void createCompilationDBAction();

View File

@@ -1,729 +0,0 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "clangbatchfileprocessor.h"
#include <clangcodemodel/clangeditordocumentprocessor.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/icore.h>
#include <cppeditor/cpptoolsreuse.h>
#include <cppeditor/cpptoolstestcase.h>
#include <cppeditor/modelmanagertesthelper.h>
#include <cppeditor/projectinfo.h>
#include <projectexplorer/projectexplorer.h>
#include <texteditor/codeassist/assistinterface.h>
#include <texteditor/codeassist/assistproposalitem.h>
#include <texteditor/codeassist/completionassistprovider.h>
#include <texteditor/codeassist/genericproposalmodel.h>
#include <texteditor/codeassist/iassistprocessor.h>
#include <texteditor/codeassist/iassistproposal.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include <utils/environment.h>
#include <utils/executeondestruction.h>
#include <utils/qtcassert.h>
#include <QDebug>
#include <QElapsedTimer>
#include <QFileInfo>
#include <QLoggingCategory>
#include <QSharedPointer>
#include <QString>
#include <QThread>
using namespace ProjectExplorer;
namespace ClangCodeModel {
namespace Internal {
static Q_LOGGING_CATEGORY(debug, "qtc.clangcodemodel.batch", QtWarningMsg);
static int timeOutFromEnvironmentVariable()
{
bool isConversionOk = false;
const int intervalAsInt = Utils::qtcEnvironmentVariableIntValue("QTC_CLANG_BATCH_TIMEOUT",
&isConversionOk);
if (!isConversionOk) {
qCDebug(debug, "Environment variable QTC_CLANG_BATCH_TIMEOUT is not set, assuming 30000.");
return 30000;
}
return intervalAsInt;
}
int timeOutInMs()
{
static int timeOut = timeOutFromEnvironmentVariable();
return timeOut;
}
namespace {
class BatchFileLineTokenizer
{
public:
BatchFileLineTokenizer(const QString &line);
QString nextToken();
private:
const QChar *advanceToTokenBegin();
const QChar *advanceToTokenEnd();
bool atEnd() const;
bool atWhiteSpace() const;
bool atQuotationMark() const;
private:
bool m_isWithinQuotation = false;
QString m_line;
const QChar *m_currentChar;
};
BatchFileLineTokenizer::BatchFileLineTokenizer(const QString &line)
: m_line(line)
, m_currentChar(m_line.unicode())
{
}
QString BatchFileLineTokenizer::nextToken()
{
if (const QChar *tokenBegin = advanceToTokenBegin()) {
if (const QChar *tokenEnd = advanceToTokenEnd()) {
const int length = tokenEnd - tokenBegin;
return QString(tokenBegin, length);
}
}
return QString();
}
const QChar *BatchFileLineTokenizer::advanceToTokenBegin()
{
m_isWithinQuotation = false;
forever {
if (atEnd())
return nullptr;
if (atQuotationMark()) {
m_isWithinQuotation = true;
++m_currentChar;
return m_currentChar;
}
if (!atWhiteSpace())
return m_currentChar;
++m_currentChar;
}
}
const QChar *BatchFileLineTokenizer::advanceToTokenEnd()
{
forever {
if (m_isWithinQuotation) {
if (atEnd()) {
qWarning("ClangBatchFileProcessor: error: unfinished quotation.");
return nullptr;
}
if (atQuotationMark())
return m_currentChar++;
} else if (atWhiteSpace() || atEnd()) {
return m_currentChar;
}
++m_currentChar;
}
}
bool BatchFileLineTokenizer::atEnd() const
{
return *m_currentChar == QLatin1Char('\0');
}
bool BatchFileLineTokenizer::atWhiteSpace() const
{
return *m_currentChar == ' '
|| *m_currentChar == '\t'
|| *m_currentChar == '\n';
}
bool BatchFileLineTokenizer::atQuotationMark() const
{
return *m_currentChar == '"';
}
struct CommandContext {
QString filePath;
int lineNumber = -1;
};
class Command
{
public:
using Ptr = QSharedPointer<Command>;
public:
Command(const CommandContext &context) : m_commandContext(context) {}
virtual ~Command() = default;
const CommandContext &context() const { return m_commandContext; }
virtual bool run() { return true; }
private:
const CommandContext m_commandContext;
};
class OpenProjectCommand : public Command
{
public:
OpenProjectCommand(const CommandContext &context,
const QString &projectFilePath);
bool run() override;
static Command::Ptr parse(BatchFileLineTokenizer &arguments,
const CommandContext &context);
private:
QString m_projectFilePath;
};
OpenProjectCommand::OpenProjectCommand(const CommandContext &context,
const QString &projectFilePath)
: Command(context)
, m_projectFilePath(projectFilePath)
{
}
bool OpenProjectCommand::run()
{
qCDebug(debug) << "line" << context().lineNumber << "OpenProjectCommand" << m_projectFilePath;
const ProjectExplorerPlugin::OpenProjectResult openProjectSucceeded
= ProjectExplorerPlugin::openProject(Utils::FilePath::fromString(m_projectFilePath));
QTC_ASSERT(openProjectSucceeded, return false);
Project *project = openProjectSucceeded.project();
project->configureAsExampleProject(nullptr);
return CppEditor::Tests::TestCase::waitUntilProjectIsFullyOpened(project, timeOutInMs());
}
Command::Ptr OpenProjectCommand::parse(BatchFileLineTokenizer &arguments,
const CommandContext &context)
{
const QString projectFilePath = arguments.nextToken();
if (projectFilePath.isEmpty()) {
qWarning("%s:%d: error: No project file path given.",
qPrintable(context.filePath),
context.lineNumber);
return Command::Ptr();
}
const QString absoluteProjectFilePath = QFileInfo(projectFilePath).absoluteFilePath();
return Command::Ptr(new OpenProjectCommand(context, absoluteProjectFilePath));
}
class OpenDocumentCommand : public Command
{
public:
OpenDocumentCommand(const CommandContext &context,
const QString &documentFilePath);
bool run() override;
static Command::Ptr parse(BatchFileLineTokenizer &arguments, const CommandContext &context);
private:
Utils::FilePath m_documentFilePath;
};
OpenDocumentCommand::OpenDocumentCommand(const CommandContext &context,
const QString &documentFilePath)
: Command(context)
, m_documentFilePath(Utils::FilePath::fromString(documentFilePath))
{
}
class WaitForUpdatedCodeWarnings : public QObject
{
public:
WaitForUpdatedCodeWarnings(ClangEditorDocumentProcessor *processor);
bool wait(int timeOutInMs) const;
private:
void onCodeWarningsUpdated() { m_gotResults = true; }
private:
bool m_gotResults = false;
};
WaitForUpdatedCodeWarnings::WaitForUpdatedCodeWarnings(ClangEditorDocumentProcessor *processor)
{
connect(processor,
&ClangEditorDocumentProcessor::codeWarningsUpdated,
this, &WaitForUpdatedCodeWarnings::onCodeWarningsUpdated);
}
bool WaitForUpdatedCodeWarnings::wait(int timeOutInMs) const
{
QElapsedTimer time;
time.start();
forever {
if (time.elapsed() > timeOutInMs) {
qWarning("WaitForUpdatedCodeWarnings: timeout of %d ms reached.", timeOutInMs);
return false;
}
if (m_gotResults)
return true;
QCoreApplication::processEvents();
QThread::msleep(20);
}
}
bool OpenDocumentCommand::run()
{
qCDebug(debug) << "line" << context().lineNumber << "OpenDocumentCommand" << m_documentFilePath;
const bool openEditorSucceeded = Core::EditorManager::openEditor(m_documentFilePath);
QTC_ASSERT(openEditorSucceeded, return false);
auto *processor = ClangEditorDocumentProcessor::get(m_documentFilePath);
QTC_ASSERT(processor, return false);
WaitForUpdatedCodeWarnings waiter(processor);
return waiter.wait(timeOutInMs());
}
Command::Ptr OpenDocumentCommand::parse(BatchFileLineTokenizer &arguments,
const CommandContext &context)
{
const QString documentFilePath = arguments.nextToken();
if (documentFilePath.isEmpty()) {
qWarning("%s:%d: error: No document file path given.",
qPrintable(context.filePath),
context.lineNumber);
return Command::Ptr();
}
const QString absoluteDocumentFilePath = QFileInfo(documentFilePath).absoluteFilePath();
return Command::Ptr(new OpenDocumentCommand(context, absoluteDocumentFilePath));
}
class CloseAllDocuments : public Command
{
public:
CloseAllDocuments(const CommandContext &context);
bool run() override;
static Command::Ptr parse(BatchFileLineTokenizer &arguments, const CommandContext &context);
};
CloseAllDocuments::CloseAllDocuments(const CommandContext &context)
: Command(context)
{
}
bool CloseAllDocuments::run()
{
qCDebug(debug) << "line" << context().lineNumber << "CloseAllDocuments";
return Core::EditorManager::closeAllEditors(/*askAboutModifiedEditors=*/ false);
}
Command::Ptr CloseAllDocuments::parse(BatchFileLineTokenizer &arguments,
const CommandContext &context)
{
const QString argument = arguments.nextToken();
if (!argument.isEmpty()) {
qWarning("%s:%d: error: Unexpected argument.",
qPrintable(context.filePath),
context.lineNumber);
return Command::Ptr();
}
return Command::Ptr(new CloseAllDocuments(context));
}
class InsertTextCommand : public Command
{
public:
// line and column are 1-based
InsertTextCommand(const CommandContext &context, const QString &text);
bool run() override;
static Command::Ptr parse(BatchFileLineTokenizer &arguments,
const CommandContext &context);
private:
const QString m_textToInsert;
};
InsertTextCommand::InsertTextCommand(const CommandContext &context, const QString &text)
: Command(context)
, m_textToInsert(text)
{
}
TextEditor::BaseTextEditor *currentTextEditor()
{
return qobject_cast<TextEditor::BaseTextEditor*>(Core::EditorManager::currentEditor());
}
bool InsertTextCommand::run()
{
qCDebug(debug) << "line" << context().lineNumber << "InsertTextCommand" << m_textToInsert;
TextEditor::BaseTextEditor *editor = currentTextEditor();
QTC_ASSERT(editor, return false);
const Utils::FilePath documentFilePath = editor->document()->filePath();
auto processor = ClangEditorDocumentProcessor::get(documentFilePath);
QTC_ASSERT(processor, return false);
editor->insert(m_textToInsert);
WaitForUpdatedCodeWarnings waiter(processor);
return waiter.wait(timeOutInMs());
}
Command::Ptr InsertTextCommand::parse(BatchFileLineTokenizer &arguments,
const CommandContext &context)
{
const QString textToInsert = arguments.nextToken();
if (textToInsert.isEmpty()) {
qWarning("%s:%d: error: No text to insert given.",
qPrintable(context.filePath),
context.lineNumber);
return Command::Ptr();
}
return Command::Ptr(new InsertTextCommand(context, textToInsert));
}
class SetCursorCommand : public Command
{
public:
// line and column are 1-based
SetCursorCommand(const CommandContext &context, int line, int column);
bool run() override;
static Command::Ptr parse(BatchFileLineTokenizer &arguments,
const CommandContext &context);
private:
int m_line;
int m_column;
};
SetCursorCommand::SetCursorCommand(const CommandContext &context, int line, int column)
: Command(context)
, m_line(line)
, m_column(column)
{
}
bool SetCursorCommand::run()
{
qCDebug(debug) << "line" << context().lineNumber << "SetCursorCommand" << m_line << m_column;
TextEditor::BaseTextEditor *editor = currentTextEditor();
QTC_ASSERT(editor, return false);
editor->gotoLine(m_line, m_column - 1);
return true;
}
Command::Ptr SetCursorCommand::parse(BatchFileLineTokenizer &arguments,
const CommandContext &context)
{
// Process line
const QString line = arguments.nextToken();
if (line.isEmpty()) {
qWarning("%s:%d: error: No line number given.",
qPrintable(context.filePath),
context.lineNumber);
return Command::Ptr();
}
bool converted = false;
const int lineNumber = line.toInt(&converted);
if (!converted) {
qWarning("%s:%d: error: Invalid line number.",
qPrintable(context.filePath),
context.lineNumber);
return Command::Ptr();
}
// Process column
const QString column = arguments.nextToken();
if (column.isEmpty()) {
qWarning("%s:%d: error: No column number given.",
qPrintable(context.filePath),
context.lineNumber);
return Command::Ptr();
}
converted = false;
const int columnNumber = column.toInt(&converted);
if (!converted) {
qWarning("%s:%d: error: Invalid column number.",
qPrintable(context.filePath),
context.lineNumber);
return Command::Ptr();
}
return Command::Ptr(new SetCursorCommand(context, lineNumber, columnNumber));
}
class ProcessEventsCommand : public Command
{
public:
ProcessEventsCommand(const CommandContext &context, int durationInMs);
bool run() override;
static Command::Ptr parse(BatchFileLineTokenizer &arguments,
const CommandContext &context);
private:
int m_durationInMs;
};
ProcessEventsCommand::ProcessEventsCommand(const CommandContext &context,
int durationInMs)
: Command(context)
, m_durationInMs(durationInMs)
{
}
bool ProcessEventsCommand::run()
{
qCDebug(debug) << "line" << context().lineNumber << "ProcessEventsCommand" << m_durationInMs;
QElapsedTimer time;
time.start();
forever {
if (time.elapsed() > m_durationInMs)
return true;
QCoreApplication::processEvents();
QThread::msleep(20);
}
}
Command::Ptr ProcessEventsCommand::parse(BatchFileLineTokenizer &arguments,
const CommandContext &context)
{
const QString durationInMsText = arguments.nextToken();
if (durationInMsText.isEmpty()) {
qWarning("%s:%d: error: No duration given.",
qPrintable(context.filePath),
context.lineNumber);
return Command::Ptr();
}
bool converted = false;
const int durationInMs = durationInMsText.toInt(&converted);
if (!converted) {
qWarning("%s:%d: error: Invalid duration given.",
qPrintable(context.filePath),
context.lineNumber);
return Command::Ptr();
}
return Command::Ptr(new ProcessEventsCommand(context, durationInMs));
}
class BatchFileReader
{
public:
BatchFileReader(const QString &filePath);
bool isFilePathValid() const;
QString read() const;
private:
const QString m_batchFilePath;
};
BatchFileReader::BatchFileReader(const QString &filePath)
: m_batchFilePath(filePath)
{
}
bool BatchFileReader::isFilePathValid() const
{
QFileInfo fileInfo(m_batchFilePath);
return !m_batchFilePath.isEmpty()
&& fileInfo.isFile()
&& fileInfo.isReadable();
}
QString BatchFileReader::read() const
{
QFile file(m_batchFilePath);
QTC_CHECK(file.open(QFile::ReadOnly | QFile::Text));
return QString::fromLocal8Bit(file.readAll());
}
class BatchFileParser
{
public:
BatchFileParser(const QString &filePath,
const QString &commands);
bool parse();
QVector<Command::Ptr> commands() const;
private:
bool advanceLine();
QString currentLine() const;
bool parseLine(const QString &line);
private:
using ParseFunction = Command::Ptr (*)(BatchFileLineTokenizer &, const CommandContext &);
using CommandToParseFunction = QHash<QString, ParseFunction>;
CommandToParseFunction m_commandParsers;
int m_currentLineIndex = -1;
CommandContext m_context;
QStringList m_lines;
QVector<Command::Ptr> m_commands;
};
BatchFileParser::BatchFileParser(const QString &filePath,
const QString &commands)
: m_lines(commands.split('\n'))
{
m_context.filePath = filePath;
m_commandParsers.insert("openProject", &OpenProjectCommand::parse);
m_commandParsers.insert("openDocument", &OpenDocumentCommand::parse);
m_commandParsers.insert("closeAllDocuments", &CloseAllDocuments::parse);
m_commandParsers.insert("setCursor", &SetCursorCommand::parse);
m_commandParsers.insert("insertText", &InsertTextCommand::parse);
m_commandParsers.insert("processEvents", &ProcessEventsCommand::parse);
}
bool BatchFileParser::parse()
{
while (advanceLine()) {
const QString line = currentLine().trimmed();
if (line.isEmpty() || line.startsWith('#'))
continue;
if (!parseLine(line))
return false;
}
return true;
}
QVector<Command::Ptr> BatchFileParser::commands() const
{
return m_commands;
}
bool BatchFileParser::advanceLine()
{
++m_currentLineIndex;
m_context.lineNumber = m_currentLineIndex + 1;
return m_currentLineIndex < m_lines.size();
}
QString BatchFileParser::currentLine() const
{
return m_lines[m_currentLineIndex];
}
bool BatchFileParser::parseLine(const QString &line)
{
BatchFileLineTokenizer tokenizer(line);
QString command = tokenizer.nextToken();
QTC_CHECK(!command.isEmpty());
if (const ParseFunction parseFunction = m_commandParsers.value(command)) {
if (Command::Ptr cmd = parseFunction(tokenizer, m_context)) {
m_commands.append(cmd);
return true;
}
return false;
}
qWarning("%s:%d: error: Unknown command \"%s\".",
qPrintable(m_context.filePath),
m_context.lineNumber,
qPrintable(command));
return false;
}
} // anonymous namespace
static QString applySubstitutions(const QString &filePath, const QString &text)
{
const QString dirPath = QFileInfo(filePath).absolutePath();
QString result = text;
result.replace("${PWD}", dirPath);
return result;
}
bool runClangBatchFile(const QString &filePath)
{
qWarning("ClangBatchFileProcessor: Running \"%s\".", qPrintable(filePath));
BatchFileReader reader(filePath);
QTC_ASSERT(reader.isFilePathValid(), return false);
const QString fileContent = reader.read();
const QString fileContentWithSubstitutionsApplied = applySubstitutions(filePath, fileContent);
BatchFileParser parser(filePath, fileContentWithSubstitutionsApplied);
QTC_ASSERT(parser.parse(), return false);
const QVector<Command::Ptr> commands = parser.commands();
Utils::ExecuteOnDestruction closeAllEditors([] {
qWarning("ClangBatchFileProcessor: Finished, closing all documents.");
QTC_CHECK(Core::EditorManager::closeAllEditors(/*askAboutModifiedEditors=*/ false));
});
for (const Command::Ptr &command : commands) {
const bool runSucceeded = command->run();
QCoreApplication::processEvents(); // Update GUI
if (!runSucceeded) {
const CommandContext context = command->context();
qWarning("%s:%d: Failed to run.",
qPrintable(context.filePath),
context.lineNumber);
return false;
}
}
return true;
}
} // namespace Internal
} // namespace ClangCodeModel

View File

@@ -1,16 +0,0 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <QString>
namespace ClangCodeModel {
namespace Internal {
int timeOutInMs();
bool runClangBatchFile(const QString &filePath);
} // namespace Internal
} // namespace ClangCodeModel

View File

@@ -3,7 +3,6 @@
#include "clangdtests.h" #include "clangdtests.h"
#include "clangbatchfileprocessor.h"
#include "../clangdclient.h" #include "../clangdclient.h"
#include "../clangmodelmanagersupport.h" #include "../clangmodelmanagersupport.h"
@@ -69,6 +68,27 @@ static QString qrcPath(const QString &relativeFilePath)
return ":/unittests/ClangCodeModel/" + relativeFilePath; return ":/unittests/ClangCodeModel/" + relativeFilePath;
} }
static Q_LOGGING_CATEGORY(debug, "qtc.clangcodemodel.batch", QtWarningMsg);
static int timeOutFromEnvironmentVariable()
{
bool isConversionOk = false;
const int intervalAsInt = Utils::qtcEnvironmentVariableIntValue("QTC_CLANG_BATCH_TIMEOUT",
&isConversionOk);
if (!isConversionOk) {
qCDebug(debug, "Environment variable QTC_CLANG_BATCH_TIMEOUT is not set, assuming 30000.");
return 30000;
}
return intervalAsInt;
}
int timeOutInMs()
{
static int timeOut = timeOutFromEnvironmentVariable();
return timeOut;
}
ClangdTest::~ClangdTest() ClangdTest::~ClangdTest()
{ {
EditorManager::closeAllEditors(false); EditorManager::closeAllEditors(false);