diff options
Diffstat (limited to 'src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp')
-rw-r--r-- | src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp | 729 |
1 files changed, 0 insertions, 729 deletions
diff --git a/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp b/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp deleted file mode 100644 index 1f0219df997..00000000000 --- a/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp +++ /dev/null @@ -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 |