logic: made parsing interruptable by introducing TaskScheduler
This change introduces the TaskScheduler, which queues and processes Tasks on a separate thread. The Task class provides a common interface for deriving all specific tasks. A task can split it's processing into multiple update calls. The TaskScheduler will update a task until it is finished or interrupt it when necessary. TaskGroups can be used to bundle multiple Tasks together. So far only TaskGroupSequential was implemented which runs the Tasks in the set order. TaskParseCxx utilizes the CxxParser to parse each source file in a single update call. Parsing can be interrupted using the ESC key. The Statusbar shows the parsing progress.
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include "qt/view/QtViewWidgetWrapper.h"
|
||||
#include "utility/logging/logging.h"
|
||||
#include "utility/messaging/type/MessageFind.h"
|
||||
#include "utility/messaging/type/MessageInterruptTasks.h"
|
||||
#include "utility/messaging/type/MessageLoadProject.h"
|
||||
#include "utility/messaging/type/MessageLoadSource.h"
|
||||
#include "utility/messaging/type/MessageRedo.h"
|
||||
@@ -36,7 +37,9 @@ QtMainWindow::QtMainWindow()
|
||||
setupFindMenu();
|
||||
setupHelpMenu();
|
||||
|
||||
// Need to call loadLayout here for right DockWidgetsize on Linux
|
||||
setupShortcuts();
|
||||
|
||||
// Need to call loadLayout here for right DockWidget size on Linux
|
||||
// Seconde call is in Application.cpp
|
||||
loadLayout();
|
||||
}
|
||||
@@ -45,94 +48,6 @@ QtMainWindow::~QtMainWindow()
|
||||
{
|
||||
}
|
||||
|
||||
void QtMainWindow::about()
|
||||
{
|
||||
QMessageBox::about(
|
||||
this,
|
||||
tr("About"),
|
||||
tr(
|
||||
"Developed by:\n\n"
|
||||
"Manuel Dobusch\n"
|
||||
"Eberhard Gräther\n"
|
||||
"Malte Langkabel\n"
|
||||
"Victoria Pfausler\n"
|
||||
"Andreas Stallinger\n"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void QtMainWindow::newProject()
|
||||
{
|
||||
QString sourceDir = QFileDialog::getExistingDirectory(this, tr("Open Directory"));
|
||||
|
||||
if (!sourceDir.isEmpty())
|
||||
{
|
||||
MessageLoadSource(sourceDir.toStdString()).dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
void QtMainWindow::openProject(const QString &path)
|
||||
{
|
||||
QString fileName = path;
|
||||
|
||||
if (fileName.isNull())
|
||||
{
|
||||
fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", "XML Files (*.xml)");
|
||||
}
|
||||
|
||||
if (!fileName.isEmpty())
|
||||
{
|
||||
MessageLoadProject(fileName.toStdString()).dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
void QtMainWindow::undo()
|
||||
{
|
||||
MessageUndo().dispatch();
|
||||
}
|
||||
|
||||
void QtMainWindow::redo()
|
||||
{
|
||||
MessageRedo().dispatch();
|
||||
}
|
||||
|
||||
void QtMainWindow::saveProject()
|
||||
{
|
||||
MessageSaveProject("").dispatch();
|
||||
}
|
||||
|
||||
void QtMainWindow::saveAsProject()
|
||||
{
|
||||
QString filename = "";
|
||||
filename = QFileDialog::getSaveFileName(this, "Save File as", "", "XML Files(*.xml)");
|
||||
|
||||
if(!filename.isEmpty())
|
||||
{
|
||||
MessageSaveProject(filename.toStdString()).dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
void QtMainWindow::find()
|
||||
{
|
||||
MessageFind().dispatch();
|
||||
}
|
||||
|
||||
void QtMainWindow::closeWindow()
|
||||
{
|
||||
QApplication* app = dynamic_cast<QApplication*>(QCoreApplication::instance());
|
||||
|
||||
QWidget* activeWindow = app->activeWindow();
|
||||
if (activeWindow)
|
||||
{
|
||||
activeWindow->close();
|
||||
}
|
||||
}
|
||||
|
||||
void QtMainWindow::refresh()
|
||||
{
|
||||
MessageRefresh().dispatch();
|
||||
}
|
||||
|
||||
void QtMainWindow::addView(View* view)
|
||||
{
|
||||
QDockWidget* dock = new QDockWidget(tr(view->getName().c_str()), this);
|
||||
@@ -207,6 +122,99 @@ bool QtMainWindow::event(QEvent* event)
|
||||
return QMainWindow::event(event);
|
||||
}
|
||||
|
||||
void QtMainWindow::about()
|
||||
{
|
||||
QMessageBox::about(
|
||||
this,
|
||||
tr("About"),
|
||||
tr(
|
||||
"Developed by:\n\n"
|
||||
"Manuel Dobusch\n"
|
||||
"Eberhard Gräther\n"
|
||||
"Malte Langkabel\n"
|
||||
"Victoria Pfausler\n"
|
||||
"Andreas Stallinger\n"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void QtMainWindow::newProject()
|
||||
{
|
||||
QString sourceDir = QFileDialog::getExistingDirectory(this, tr("Open Directory"));
|
||||
|
||||
if (!sourceDir.isEmpty())
|
||||
{
|
||||
MessageLoadSource(sourceDir.toStdString()).dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
void QtMainWindow::openProject(const QString &path)
|
||||
{
|
||||
QString fileName = path;
|
||||
|
||||
if (fileName.isNull())
|
||||
{
|
||||
fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", "XML Files (*.xml)");
|
||||
}
|
||||
|
||||
if (!fileName.isEmpty())
|
||||
{
|
||||
MessageLoadProject(fileName.toStdString()).dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
void QtMainWindow::find()
|
||||
{
|
||||
MessageFind().dispatch();
|
||||
}
|
||||
|
||||
void QtMainWindow::closeWindow()
|
||||
{
|
||||
QApplication* app = dynamic_cast<QApplication*>(QCoreApplication::instance());
|
||||
|
||||
QWidget* activeWindow = app->activeWindow();
|
||||
if (activeWindow)
|
||||
{
|
||||
activeWindow->close();
|
||||
}
|
||||
}
|
||||
|
||||
void QtMainWindow::refresh()
|
||||
{
|
||||
MessageRefresh().dispatch();
|
||||
}
|
||||
|
||||
void QtMainWindow::saveProject()
|
||||
{
|
||||
MessageSaveProject("").dispatch();
|
||||
}
|
||||
|
||||
void QtMainWindow::saveAsProject()
|
||||
{
|
||||
QString filename = "";
|
||||
filename = QFileDialog::getSaveFileName(this, "Save File as", "", "XML Files(*.xml)");
|
||||
|
||||
if(!filename.isEmpty())
|
||||
{
|
||||
MessageSaveProject(filename.toStdString()).dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
void QtMainWindow::undo()
|
||||
{
|
||||
MessageUndo().dispatch();
|
||||
}
|
||||
|
||||
void QtMainWindow::redo()
|
||||
{
|
||||
MessageRedo().dispatch();
|
||||
}
|
||||
|
||||
void QtMainWindow::handleEscapeShortcut()
|
||||
{
|
||||
MessageInterruptTasks().dispatch();
|
||||
}
|
||||
|
||||
void QtMainWindow::setupProjectMenu()
|
||||
{
|
||||
QMenu *menu = new QMenu(tr("&Project"), this);
|
||||
@@ -254,6 +262,12 @@ void QtMainWindow::setupHelpMenu()
|
||||
menu->addAction(tr("About &Qt"), QCoreApplication::instance(), SLOT(aboutQt()));
|
||||
}
|
||||
|
||||
void QtMainWindow::setupShortcuts()
|
||||
{
|
||||
m_escapeShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
||||
connect(m_escapeShortcut, SIGNAL(activated()), SLOT(handleEscapeShortcut()));
|
||||
}
|
||||
|
||||
QDockWidget* QtMainWindow::getDockWidgetForView(View* view) const
|
||||
{
|
||||
for (size_t i = 0; i < m_dockWidgets.size(); i++)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <QShortcut>
|
||||
#include <QtWidgets/QMainWindow>
|
||||
|
||||
class QDockWidget;
|
||||
@@ -41,6 +42,8 @@ public slots:
|
||||
void undo();
|
||||
void redo();
|
||||
|
||||
void handleEscapeShortcut();
|
||||
|
||||
private:
|
||||
void setupEditMenu();
|
||||
void setupProjectMenu();
|
||||
@@ -48,9 +51,13 @@ private:
|
||||
void setupFindMenu();
|
||||
void setupHelpMenu();
|
||||
|
||||
void setupShortcuts();
|
||||
|
||||
QDockWidget* getDockWidgetForView(View* view) const;
|
||||
|
||||
std::vector<std::pair<View*, QDockWidget*>> m_dockWidgets;
|
||||
|
||||
QShortcut* m_escapeShortcut;
|
||||
};
|
||||
|
||||
#endif // QT_MAIN_WINDOW_H
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "utility/logging/logging.h"
|
||||
#include "utility/messaging/MessageQueue.h"
|
||||
#include "utility/messaging/type/MessageActivateTokens.h"
|
||||
#include "utility/scheduling/TaskScheduler.h"
|
||||
|
||||
#include "component/view/MainView.h"
|
||||
#include "component/view/ViewFactory.h"
|
||||
@@ -40,10 +41,12 @@ std::shared_ptr<Application> Application::create(ViewFactory* viewFactory)
|
||||
Application::Application()
|
||||
{
|
||||
MessageQueue::getInstance()->startMessageLoopThreaded();
|
||||
TaskScheduler::getInstance()->startSchedulerLoopThreaded();
|
||||
}
|
||||
|
||||
Application::~Application()
|
||||
{
|
||||
TaskScheduler::getInstance()->stopSchedulerLoop();
|
||||
MessageQueue::getInstance()->stopMessageLoop();
|
||||
m_mainView->saveLayout();
|
||||
}
|
||||
|
||||
@@ -142,6 +142,9 @@ add_files(
|
||||
data/name/NameHierarchy.cpp
|
||||
data/name/NameHierarchy.h
|
||||
|
||||
data/parser/cxx/TaskParseCxx.cpp
|
||||
data/parser/cxx/TaskParseCxx.h
|
||||
|
||||
data/parser/ParseFunction.cpp
|
||||
data/parser/ParseFunction.h
|
||||
data/parser/ParseLocation.cpp
|
||||
@@ -241,6 +244,7 @@ add_files(
|
||||
utility/messaging/type/MessageFinishedParsing.h
|
||||
utility/messaging/type/MessageGraphNodeExpand.h
|
||||
utility/messaging/type/MessageGraphNodeMove.h
|
||||
utility/messaging/type/MessageInterruptTasks.h
|
||||
utility/messaging/type/MessageLoadProject.h
|
||||
utility/messaging/type/MessageLoadSource.h
|
||||
utility/messaging/type/MessageRefresh.h
|
||||
@@ -260,6 +264,15 @@ add_files(
|
||||
utility/messaging/MessageQueue.cpp
|
||||
utility/messaging/MessageQueue.h
|
||||
|
||||
utility/scheduling/Task.cpp
|
||||
utility/scheduling/Task.h
|
||||
utility/scheduling/TaskGroup.cpp
|
||||
utility/scheduling/TaskGroup.h
|
||||
utility/scheduling/TaskGroupSequential.cpp
|
||||
utility/scheduling/TaskGroupSequential.h
|
||||
utility/scheduling/TaskScheduler.cpp
|
||||
utility/scheduling/TaskScheduler.h
|
||||
|
||||
utility/text/Dictionary.cpp
|
||||
utility/text/Dictionary.h
|
||||
utility/text/TextAccess.cpp
|
||||
|
||||
+64
-42
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "data/access/StorageAccessProxy.h"
|
||||
#include "data/graph/Token.h"
|
||||
#include "data/parser/cxx/CxxParser.h"
|
||||
#include "data/parser/cxx/TaskParseCxx.h"
|
||||
#include "settings/ApplicationSettings.h"
|
||||
#include "settings/ProjectSettings.h"
|
||||
|
||||
@@ -24,29 +24,31 @@ Project::~Project()
|
||||
bool Project::loadProjectSettings(const std::string& projectSettingsFile)
|
||||
{
|
||||
bool success = ProjectSettings::getInstance()->load(projectSettingsFile);
|
||||
if(success)
|
||||
if (success)
|
||||
{
|
||||
m_projectSettingsFilepath = projectSettingsFile;
|
||||
|
||||
createFileManager();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Project::saveProjectSettings( const std::string& projectSettingsFile )
|
||||
bool Project::saveProjectSettings(const std::string& projectSettingsFile)
|
||||
{
|
||||
if(!projectSettingsFile.empty())
|
||||
if (projectSettingsFile.size())
|
||||
{
|
||||
m_projectSettingsFilepath = projectSettingsFile;
|
||||
ProjectSettings::getInstance()->save(projectSettingsFile);
|
||||
}
|
||||
else if (!m_projectSettingsFilepath.empty())
|
||||
{
|
||||
ProjectSettings::getInstance()->save(m_projectSettingsFilepath);
|
||||
}
|
||||
else
|
||||
|
||||
if (!m_projectSettingsFilepath.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
LOG_INFO_STREAM(<< "Projectsettings saved in File: " << m_projectSettingsFilepath);
|
||||
|
||||
ProjectSettings::getInstance()->save(m_projectSettingsFilepath);
|
||||
|
||||
LOG_INFO_STREAM(<< "ProjectSettings saved to file: " << m_projectSettingsFilepath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -54,12 +56,21 @@ void Project::clearProjectSettings()
|
||||
{
|
||||
m_projectSettingsFilepath.clear();
|
||||
ProjectSettings::getInstance()->clear();
|
||||
|
||||
m_fileManager.reset();
|
||||
}
|
||||
|
||||
bool Project::setSourceDirectoryPath(const std::string& sourceDirectoryPath)
|
||||
{
|
||||
m_projectSettingsFilepath = sourceDirectoryPath + "/ProjectSettings.xml";
|
||||
return ProjectSettings::getInstance()->setSourcePaths(std::vector<std::string>(1, sourceDirectoryPath));
|
||||
bool success = ProjectSettings::getInstance()->setSourcePaths(std::vector<std::string>(1, sourceDirectoryPath));
|
||||
|
||||
if (success)
|
||||
{
|
||||
createFileManager();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void Project::clearStorage()
|
||||
@@ -72,25 +83,13 @@ void Project::clearStorage()
|
||||
|
||||
void Project::parseCode()
|
||||
{
|
||||
std::shared_ptr<ProjectSettings> projSettings = ProjectSettings::getInstance();
|
||||
std::shared_ptr<ApplicationSettings> appSettings = ApplicationSettings::getInstance();
|
||||
|
||||
std::vector<std::string> sourcePaths = projSettings->getSourcePaths();
|
||||
if (!sourcePaths.size())
|
||||
if (!m_fileManager)
|
||||
{
|
||||
LOG_ERROR("No FileManger was created.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> includePaths(sourcePaths);
|
||||
|
||||
// TODO: move this creation to another place (after projectsettings have been loaded)
|
||||
if (!m_fileManager)
|
||||
{
|
||||
std::vector<std::string> sourceExtensions = ProjectSettings::getInstance()->getSourceExtensions();
|
||||
std::vector<std::string> includeExtensions = ProjectSettings::getInstance()->getHeaderExtensions();
|
||||
|
||||
m_fileManager = std::make_shared<FileManager>(sourcePaths, includePaths, sourceExtensions, includeExtensions);
|
||||
}
|
||||
std::shared_ptr<ProjectSettings> projSettings = ProjectSettings::getInstance();
|
||||
|
||||
m_fileManager->fetchFilePaths();
|
||||
std::set<FilePath> addedFilePaths = m_fileManager->getAddedFilePaths();
|
||||
@@ -109,36 +108,59 @@ void Project::parseCode()
|
||||
|
||||
if (filesToParse.size() == 0)
|
||||
{
|
||||
MessageFinishedParsing(0, 0, m_storage->getErrorCount()).dispatch();
|
||||
MessageFinishedParsing(0, 0, 0, m_storage->getErrorCount()).dispatch();
|
||||
return;
|
||||
}
|
||||
|
||||
Task::dispatch(std::make_shared<TaskParseCxx>(
|
||||
m_storage.get(),
|
||||
m_fileManager.get(),
|
||||
getParserArguments(),
|
||||
filesToParse
|
||||
));
|
||||
}
|
||||
|
||||
void Project::createFileManager()
|
||||
{
|
||||
std::shared_ptr<ProjectSettings> projSettings = ProjectSettings::getInstance();
|
||||
|
||||
std::vector<std::string> sourcePaths(projSettings->getSourcePaths());
|
||||
std::vector<std::string> includePaths(sourcePaths);
|
||||
|
||||
std::vector<std::string> sourceExtensions = projSettings->getSourceExtensions();
|
||||
std::vector<std::string> includeExtensions = projSettings->getHeaderExtensions();
|
||||
|
||||
if (sourcePaths.size())
|
||||
{
|
||||
m_fileManager = std::make_shared<FileManager>(sourcePaths, includePaths, sourceExtensions, includeExtensions);
|
||||
}
|
||||
}
|
||||
|
||||
Parser::Arguments Project::getParserArguments() const
|
||||
{
|
||||
std::shared_ptr<ProjectSettings> projSettings = ProjectSettings::getInstance();
|
||||
std::shared_ptr<ApplicationSettings> appSettings = ApplicationSettings::getInstance();
|
||||
|
||||
Parser::Arguments args;
|
||||
|
||||
if (!m_fileManager)
|
||||
{
|
||||
LOG_ERROR("No FileManger was created.");
|
||||
return args;
|
||||
}
|
||||
|
||||
utility::append(args.compilerFlags, projSettings->getCompilerFlags());
|
||||
utility::append(args.compilerFlags, appSettings->getCompilerFlags());
|
||||
|
||||
// Add the include paths as HeaderSearchPaths as well, so clang will also look here when searching include files.
|
||||
utility::append(args.systemHeaderSearchPaths, includePaths);
|
||||
utility::append(args.systemHeaderSearchPaths, m_fileManager->getIncludePaths());
|
||||
utility::append(args.systemHeaderSearchPaths, projSettings->getHeaderSearchPaths());
|
||||
utility::append(args.systemHeaderSearchPaths, appSettings->getHeaderSearchPaths());
|
||||
|
||||
utility::append(args.frameworkSearchPaths, projSettings->getFrameworkSearchPaths());
|
||||
utility::append(args.frameworkSearchPaths, appSettings->getFrameworkSearchPaths());
|
||||
|
||||
CxxParser parser(m_storage.get(), m_fileManager.get());
|
||||
|
||||
float duration = utility::duration(
|
||||
[&]()
|
||||
{
|
||||
parser.parseFiles(filesToParse, args);
|
||||
}
|
||||
);
|
||||
|
||||
// m_storage->logGraph();
|
||||
// m_storage->logLocations();
|
||||
|
||||
MessageFinishedParsing(filesToParse.size(), duration, m_storage->getErrorCount()).dispatch();
|
||||
return args;
|
||||
}
|
||||
|
||||
Project::Project(StorageAccessProxy* storageAccessProxy)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "utility/file/FileManager.h"
|
||||
|
||||
#include "data/parser/Parser.h"
|
||||
#include "data/Storage.h"
|
||||
|
||||
class StorageAccessProxy;
|
||||
@@ -30,6 +31,10 @@ private:
|
||||
Project(const Project&);
|
||||
Project operator=(const Project&);
|
||||
|
||||
void createFileManager();
|
||||
|
||||
Parser::Arguments getParserArguments() const;
|
||||
|
||||
std::string m_projectSettingsFilepath;
|
||||
|
||||
StorageAccessProxy* const m_storageAccessProxy;
|
||||
|
||||
@@ -30,7 +30,7 @@ void StatusBarController::handleMessage(MessageFinishedParsing* message)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Parsing Finished: ";
|
||||
ss << message->fileCount << " files, ";
|
||||
ss << message->fileCount << "/" << message->totalFileCount << " files, ";
|
||||
ss << std::setprecision(2) << std::fixed << message->parseTime << " seconds, ";
|
||||
ss << message->errorCount << " error(s)";
|
||||
|
||||
|
||||
@@ -150,11 +150,6 @@ void Storage::logLocations() const
|
||||
LOG_INFO_STREAM(<< '\n' << m_locationCollection);
|
||||
}
|
||||
|
||||
size_t Storage::getErrorCount() const
|
||||
{
|
||||
return m_errorLocationCollection.getTokenLocationCount();
|
||||
}
|
||||
|
||||
void Storage::onError(const ParseLocation& location, const std::string& message)
|
||||
{
|
||||
log("ERROR", message, location);
|
||||
@@ -198,6 +193,11 @@ void Storage::onError(const ParseLocation& location, const std::string& message)
|
||||
}
|
||||
}
|
||||
|
||||
size_t Storage::getErrorCount() const
|
||||
{
|
||||
return m_errorLocationCollection.getTokenLocationCount();
|
||||
}
|
||||
|
||||
Id Storage::onTypedefParsed(
|
||||
const ParseLocation& location, const NameHierarchy& nameHierarchy, const ParseTypeUsage& underlyingType,
|
||||
AccessType access
|
||||
|
||||
@@ -29,10 +29,9 @@ public:
|
||||
void logGraph() const;
|
||||
void logLocations() const;
|
||||
|
||||
size_t getErrorCount() const;
|
||||
|
||||
// ParserClient implementation
|
||||
virtual void onError(const ParseLocation& location, const std::string& message);
|
||||
virtual size_t getErrorCount() const;
|
||||
|
||||
virtual Id onTypedefParsed(
|
||||
const ParseLocation& location, const NameHierarchy& nameHierarchy,
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "data/parser/ParserClient.h"
|
||||
|
||||
class FilePath;
|
||||
class ParserClient;
|
||||
class TextAccess;
|
||||
|
||||
class Parser
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
virtual ~ParserClient();
|
||||
|
||||
virtual void onError(const ParseLocation& location, const std::string& message) = 0;
|
||||
virtual size_t getErrorCount() const = 0;
|
||||
|
||||
virtual Id onTypedefParsed(
|
||||
const ParseLocation& location, const NameHierarchy& nameHierarchy,
|
||||
|
||||
@@ -21,8 +21,6 @@ std::unique_ptr<clang::ASTConsumer> ASTAction::CreateASTConsumer(clang::Compiler
|
||||
|
||||
bool ASTAction::BeginSourceFileAction(clang::CompilerInstance& compiler, llvm::StringRef filePath)
|
||||
{
|
||||
m_client->onFileParsed(filePath.str());
|
||||
|
||||
clang::Preprocessor& preprocessor = compiler.getPreprocessor();
|
||||
preprocessor.addPPCallbacks(
|
||||
llvm::make_unique<PreprocessorCallbacks>(compiler.getSourceManager(), m_client, m_fileRegister));
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "data/parser/cxx/CxxParser.h"
|
||||
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
|
||||
#include "utility/file/FileManager.h"
|
||||
#include "utility/file/FileRegister.h"
|
||||
#include "utility/logging/logging.h"
|
||||
#include "utility/text/TextAccess.h"
|
||||
@@ -50,7 +53,7 @@ namespace
|
||||
|
||||
CxxParser::CxxParser(ParserClient* client, const FileManager* fileManager)
|
||||
: Parser(client)
|
||||
, m_fileManager(fileManager)
|
||||
, m_fileRegister(std::make_shared<FileRegister>(fileManager))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -60,70 +63,33 @@ CxxParser::~CxxParser()
|
||||
|
||||
void CxxParser::parseFiles(const std::vector<FilePath>& filePaths, const Arguments& arguments)
|
||||
{
|
||||
// Commandline flags passed to the programm. Everything after '--' will be interpreted by the ClangTool.
|
||||
std::vector<std::string> args = getCommandlineArguments(arguments);
|
||||
args.insert(args.begin(), "app");
|
||||
args.insert(args.begin() + 1, "--");
|
||||
|
||||
int argc = args.size();
|
||||
const char** argv = new const char*[argc];
|
||||
for (size_t i = 0; i < args.size(); i++)
|
||||
{
|
||||
argv[i] = args[i].c_str();
|
||||
}
|
||||
|
||||
std::shared_ptr<clang::tooling::FixedCompilationDatabase> compilationDatabase(
|
||||
clang::tooling::FixedCompilationDatabase::loadFromCommandLine(argc, argv)
|
||||
);
|
||||
|
||||
if (!compilationDatabase)
|
||||
{
|
||||
LOG_ERROR("Failed to load compilation database");
|
||||
return;
|
||||
}
|
||||
|
||||
FileRegister fileRegister(m_fileManager, filePaths);
|
||||
setupParsing(filePaths, arguments);
|
||||
|
||||
std::vector<std::string> sourcePaths;
|
||||
for (const FilePath& path : fileRegister.getSourceFilePaths())
|
||||
for (const FilePath& path : m_fileRegister->getUnparsedSourceFilePaths())
|
||||
{
|
||||
sourcePaths.push_back(path.absoluteStr());
|
||||
}
|
||||
|
||||
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> options = new clang::DiagnosticOptions();
|
||||
CxxDiagnosticConsumer reporter(llvm::errs(), &*options, m_client, arguments.logErrors);
|
||||
runTool(sourcePaths);
|
||||
|
||||
ASTActionFactory actionFactory(m_client, &fileRegister);
|
||||
|
||||
clang::tooling::ClangTool tool(*compilationDatabase, sourcePaths);
|
||||
tool.setDiagnosticConsumer(&reporter);
|
||||
tool.run(&actionFactory);
|
||||
|
||||
std::vector<FilePath> unparsedHeaders = fileRegister.getUnparsedIncludeFilePaths();
|
||||
std::vector<FilePath> unparsedHeaders = m_fileRegister->getUnparsedIncludeFilePaths();
|
||||
for (const FilePath& path : unparsedHeaders)
|
||||
{
|
||||
if (!fileRegister.includeFileIsParsed(path))
|
||||
if (!m_fileRegister->includeFileIsParsed(path))
|
||||
{
|
||||
clang::tooling::ClangTool tool(*compilationDatabase, std::vector<std::string>(1, path.str()));
|
||||
tool.setDiagnosticConsumer(&reporter);
|
||||
tool.run(&actionFactory);
|
||||
runTool(std::vector<std::string>(1, path.str()));
|
||||
}
|
||||
}
|
||||
|
||||
delete argv;
|
||||
}
|
||||
|
||||
void CxxParser::parseFile(std::shared_ptr<TextAccess> textAccess, const Arguments& arguments)
|
||||
{
|
||||
std::vector<std::string> args = getCommandlineArguments(arguments);
|
||||
std::shared_ptr<CxxDiagnosticConsumer> diagnostics = getDiagnostics(arguments);
|
||||
|
||||
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> options = new clang::DiagnosticOptions();
|
||||
CxxDiagnosticConsumer reporter(llvm::errs(), &*options, m_client, arguments.logErrors);
|
||||
|
||||
FileRegister fileRegister(m_fileManager, std::vector<FilePath>());
|
||||
|
||||
ASTActionFactory actionFactory(m_client, &fileRegister);
|
||||
runToolOnCodeWithArgs(&reporter, actionFactory.create(), textAccess->getText(), args);
|
||||
ASTActionFactory actionFactory(m_client, m_fileRegister.get());
|
||||
runToolOnCodeWithArgs(diagnostics.get(), actionFactory.create(), textAccess->getText(), args);
|
||||
}
|
||||
|
||||
std::vector<std::string> CxxParser::getCommandlineArguments(const Arguments& arguments) const
|
||||
@@ -165,3 +131,65 @@ std::vector<std::string> CxxParser::getCommandlineArguments(const Arguments& arg
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
std::shared_ptr<clang::tooling::FixedCompilationDatabase> CxxParser::getCompilationDatabase(
|
||||
const Arguments& arguments
|
||||
) const {
|
||||
// Commandline flags passed to the programm. Everything after '--' will be interpreted by the ClangTool.
|
||||
std::vector<std::string> args = getCommandlineArguments(arguments);
|
||||
args.insert(args.begin(), "app");
|
||||
args.insert(args.begin() + 1, "--");
|
||||
|
||||
int argc = args.size();
|
||||
const char** argv = new const char*[argc];
|
||||
for (size_t i = 0; i < args.size(); i++)
|
||||
{
|
||||
argv[i] = args[i].c_str();
|
||||
}
|
||||
|
||||
std::shared_ptr<clang::tooling::FixedCompilationDatabase> compilationDatabase(
|
||||
clang::tooling::FixedCompilationDatabase::loadFromCommandLine(argc, argv)
|
||||
);
|
||||
|
||||
delete argv;
|
||||
|
||||
if (!compilationDatabase)
|
||||
{
|
||||
LOG_ERROR("Failed to load compilation database");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return compilationDatabase;
|
||||
}
|
||||
|
||||
std::shared_ptr<CxxDiagnosticConsumer> CxxParser::getDiagnostics(const Arguments& arguments) const
|
||||
{
|
||||
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> options = new clang::DiagnosticOptions();
|
||||
return std::make_shared<CxxDiagnosticConsumer>(llvm::errs(), &*options, m_client, arguments.logErrors);
|
||||
}
|
||||
|
||||
void CxxParser::setupParsing(const std::vector<FilePath>& filePaths, const Arguments& arguments)
|
||||
{
|
||||
m_fileRegister->setFilePaths(filePaths);
|
||||
m_compilationDatabase = getCompilationDatabase(arguments);
|
||||
m_diagnostics = getDiagnostics(arguments);
|
||||
}
|
||||
|
||||
void CxxParser::runTool(const std::vector<std::string>& files)
|
||||
{
|
||||
clang::tooling::ClangTool tool(*m_compilationDatabase, files);
|
||||
tool.setDiagnosticConsumer(m_diagnostics.get());
|
||||
|
||||
ASTActionFactory actionFactory(m_client, m_fileRegister.get());
|
||||
tool.run(&actionFactory);
|
||||
}
|
||||
|
||||
FileRegister* CxxParser::getFileRegister()
|
||||
{
|
||||
return m_fileRegister.get();
|
||||
}
|
||||
|
||||
ParserClient* CxxParser::getParserClient()
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,19 @@
|
||||
#define CXX_PARSER_H
|
||||
|
||||
#include "data/parser/Parser.h"
|
||||
#include "utility/file/FileManager.h"
|
||||
|
||||
namespace clang
|
||||
{
|
||||
namespace tooling
|
||||
{
|
||||
class FixedCompilationDatabase;
|
||||
}
|
||||
}
|
||||
|
||||
class CxxDiagnosticConsumer;
|
||||
class FileManager;
|
||||
class FileRegister;
|
||||
class TaskParseCxx;
|
||||
|
||||
class CxxParser: public Parser
|
||||
{
|
||||
@@ -10,13 +22,29 @@ public:
|
||||
CxxParser(ParserClient* client, const FileManager* fileManager);
|
||||
~CxxParser();
|
||||
|
||||
// ParserClient implementation
|
||||
virtual void parseFiles(const std::vector<FilePath>& filePaths, const Arguments& arguments);
|
||||
virtual void parseFile(std::shared_ptr<TextAccess> textAccess, const Arguments& arguments);
|
||||
|
||||
private:
|
||||
std::vector<std::string> getCommandlineArguments(const Arguments& arguments) const;
|
||||
std::shared_ptr<clang::tooling::FixedCompilationDatabase> getCompilationDatabase(const Arguments& arguments) const;
|
||||
|
||||
const FileManager* m_fileManager;
|
||||
std::shared_ptr<CxxDiagnosticConsumer> getDiagnostics(const Arguments& arguments) const;
|
||||
|
||||
// Accessed by TaskParseCxx
|
||||
void setupParsing(const std::vector<FilePath>& filePaths, const Arguments& arguments);
|
||||
void runTool(const std::vector<std::string>& files);
|
||||
|
||||
FileRegister* getFileRegister();
|
||||
ParserClient* getParserClient();
|
||||
|
||||
friend class TaskParseCxx;
|
||||
|
||||
std::shared_ptr<FileRegister> m_fileRegister;
|
||||
|
||||
std::shared_ptr<clang::tooling::FixedCompilationDatabase> m_compilationDatabase;
|
||||
std::shared_ptr<CxxDiagnosticConsumer> m_diagnostics;
|
||||
};
|
||||
|
||||
#endif // CXX_PARSER_H
|
||||
|
||||
@@ -26,6 +26,7 @@ void PreprocessorCallbacks::FileChanged(
|
||||
const clang::FileEntry *fileEntry = m_sourceManager.getFileEntryForID(m_sourceManager.getFileID(location));
|
||||
if (fileEntry && m_fileRegister->getFileManager()->hasFilePath(fileEntry->getName()))
|
||||
{
|
||||
m_client->onFileParsed(fileEntry->getName());
|
||||
m_fileRegister->markIncludeFileParsing(fileEntry->getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
#include "data/parser/cxx/TaskParseCxx.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "utility/file/FileRegister.h"
|
||||
#include "utility/messaging/type/MessageFinishedParsing.h"
|
||||
#include "utility/messaging/type/MessageStatus.h"
|
||||
|
||||
#include "data/parser/ParserClient.h"
|
||||
|
||||
TaskParseCxx::TaskParseCxx(
|
||||
ParserClient* client,
|
||||
const FileManager* fileManager,
|
||||
const Parser::Arguments& arguments,
|
||||
const std::vector<FilePath>& files
|
||||
)
|
||||
: m_parser(client, fileManager)
|
||||
, m_arguments(arguments)
|
||||
, m_files(files)
|
||||
{
|
||||
}
|
||||
|
||||
void TaskParseCxx::enter()
|
||||
{
|
||||
m_start = utility::durationStart();
|
||||
|
||||
m_parser.setupParsing(m_files, m_arguments);
|
||||
|
||||
for (const FilePath& path : m_parser.getFileRegister()->getUnparsedSourceFilePaths())
|
||||
{
|
||||
m_sourcePaths.push(path.absoluteStr());
|
||||
}
|
||||
}
|
||||
|
||||
Task::TaskState TaskParseCxx::update()
|
||||
{
|
||||
std::string sourcePath;
|
||||
bool isSource = false;
|
||||
|
||||
FileRegister* fileRegister = m_parser.getFileRegister();
|
||||
|
||||
if (m_sourcePaths.size())
|
||||
{
|
||||
sourcePath = m_sourcePaths.front();
|
||||
m_sourcePaths.pop();
|
||||
isSource = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<FilePath> unparsedHeaders = fileRegister->getUnparsedIncludeFilePaths();
|
||||
if (unparsedHeaders.size())
|
||||
{
|
||||
sourcePath = unparsedHeaders[0].str();
|
||||
}
|
||||
}
|
||||
|
||||
if (!sourcePath.size())
|
||||
{
|
||||
return Task::STATE_FINISHED;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "parsing (ESC to quit): [";
|
||||
ss << fileRegister->getParsedFilesCount() << "/" << fileRegister->getFilesCount() << "] ";
|
||||
ss << sourcePath;
|
||||
|
||||
MessageStatus(ss.str()).dispatch();
|
||||
|
||||
m_parser.runTool(std::vector<std::string>(1, sourcePath));
|
||||
|
||||
if (isSource)
|
||||
{
|
||||
fileRegister->markSourceFileParsed(sourcePath);
|
||||
}
|
||||
|
||||
return Task::STATE_RUNNING;
|
||||
}
|
||||
|
||||
void TaskParseCxx::exit()
|
||||
{
|
||||
FileRegister* fileRegister = m_parser.getFileRegister();
|
||||
|
||||
MessageFinishedParsing(
|
||||
fileRegister->getParsedFilesCount(),
|
||||
fileRegister->getFilesCount(),
|
||||
utility::duration(m_start),
|
||||
m_parser.getParserClient()->getErrorCount()
|
||||
).dispatch();
|
||||
}
|
||||
|
||||
void TaskParseCxx::interrupt()
|
||||
{
|
||||
}
|
||||
|
||||
void TaskParseCxx::revert()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef TASK_PARSE_CXX_H
|
||||
#define TASK_PARSE_CXX_H
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "utility/scheduling/Task.h"
|
||||
#include "utility/utility.h"
|
||||
|
||||
#include "data/parser/cxx/CxxParser.h"
|
||||
|
||||
class TaskParseCxx
|
||||
: public Task
|
||||
{
|
||||
public:
|
||||
TaskParseCxx(
|
||||
ParserClient* client,
|
||||
const FileManager* fileManager,
|
||||
const Parser::Arguments& arguments,
|
||||
const std::vector<FilePath>& files
|
||||
);
|
||||
|
||||
virtual void enter();
|
||||
virtual TaskState update();
|
||||
virtual void exit();
|
||||
|
||||
virtual void interrupt();
|
||||
virtual void revert();
|
||||
|
||||
private:
|
||||
CxxParser m_parser;
|
||||
const Parser::Arguments m_arguments;
|
||||
const std::vector<FilePath> m_files;
|
||||
|
||||
std::queue<std::string> m_sourcePaths;
|
||||
|
||||
utility::TimePoint m_start;
|
||||
};
|
||||
|
||||
#endif // TASK_PARSE_CXX_H
|
||||
@@ -22,6 +22,16 @@ FileManager::~FileManager()
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<std::string>& FileManager::getSourcePaths() const
|
||||
{
|
||||
return m_sourcePaths;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& FileManager::getIncludePaths() const
|
||||
{
|
||||
return m_includePaths;
|
||||
}
|
||||
|
||||
void FileManager::reset()
|
||||
{
|
||||
m_files.clear();
|
||||
|
||||
@@ -18,6 +18,9 @@ public:
|
||||
);
|
||||
~FileManager();
|
||||
|
||||
const std::vector<std::string>& getSourcePaths() const;
|
||||
const std::vector<std::string>& getIncludePaths() const;
|
||||
|
||||
void reset();
|
||||
void fetchFilePaths();
|
||||
|
||||
|
||||
@@ -3,14 +3,26 @@
|
||||
#include "utility/file/FileManager.h"
|
||||
#include "utility/file/FileSystem.h"
|
||||
|
||||
FileRegister::FileRegister(const FileManager* fileManager, const std::vector<FilePath>& filePaths)
|
||||
FileRegister::FileRegister(const FileManager* fileManager)
|
||||
: m_fileManager(fileManager)
|
||||
{
|
||||
}
|
||||
|
||||
const FileManager* FileRegister::getFileManager() const
|
||||
{
|
||||
return m_fileManager;
|
||||
}
|
||||
|
||||
void FileRegister::setFilePaths(const std::vector<FilePath>& filePaths)
|
||||
{
|
||||
m_sourceFilePaths.clear();
|
||||
m_includeFilePaths.clear();
|
||||
|
||||
for (const FilePath& path : filePaths)
|
||||
{
|
||||
if (m_fileManager->hasSourceExtension(path))
|
||||
{
|
||||
m_sourceFilePaths.push_back(path);
|
||||
m_sourceFilePaths.emplace(path, STATE_UNPARSED);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -19,29 +31,14 @@ FileRegister::FileRegister(const FileManager* fileManager, const std::vector<Fil
|
||||
}
|
||||
}
|
||||
|
||||
const FileManager* FileRegister::getFileManager() const
|
||||
std::vector<FilePath> FileRegister::getUnparsedSourceFilePaths() const
|
||||
{
|
||||
return m_fileManager;
|
||||
}
|
||||
|
||||
const std::vector<FilePath>& FileRegister::getSourceFilePaths() const
|
||||
{
|
||||
return m_sourceFilePaths;
|
||||
return getUnparsedFilePaths(m_sourceFilePaths);
|
||||
}
|
||||
|
||||
std::vector<FilePath> FileRegister::getUnparsedIncludeFilePaths() const
|
||||
{
|
||||
std::vector<FilePath> filePaths;
|
||||
|
||||
for (std::pair<FilePath, ParseState>&& p : m_includeFilePaths)
|
||||
{
|
||||
if (p.second == STATE_UNPARSED)
|
||||
{
|
||||
filePaths.push_back(p.first);
|
||||
}
|
||||
}
|
||||
|
||||
return filePaths;
|
||||
return getUnparsedFilePaths(m_includeFilePaths);
|
||||
}
|
||||
|
||||
bool FileRegister::includeFileIsParsing(const FilePath& filePath) const
|
||||
@@ -66,6 +63,17 @@ bool FileRegister::includeFileIsParsed(const FilePath& filePath) const
|
||||
return it->second == STATE_PARSED;
|
||||
}
|
||||
|
||||
void FileRegister::markSourceFileParsed(const std::string& filePath)
|
||||
{
|
||||
std::map<FilePath, ParseState>::iterator it = m_sourceFilePaths.find(FilePath(filePath));
|
||||
if (it == m_sourceFilePaths.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
it->second = STATE_PARSED;
|
||||
}
|
||||
|
||||
void FileRegister::markIncludeFileParsing(const std::string& filePath)
|
||||
{
|
||||
std::map<FilePath, ParseState>::iterator it = m_includeFilePaths.find(FilePath(filePath));
|
||||
@@ -90,3 +98,28 @@ void FileRegister::markParsingIncludeFilesParsed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<FilePath> FileRegister::getUnparsedFilePaths(const std::map<FilePath, ParseState> filePaths) const
|
||||
{
|
||||
std::vector<FilePath> files;
|
||||
|
||||
for (std::pair<FilePath, ParseState>&& p : filePaths)
|
||||
{
|
||||
if (p.second == STATE_UNPARSED)
|
||||
{
|
||||
files.push_back(p.first);
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
size_t FileRegister::getFilesCount() const
|
||||
{
|
||||
return m_sourceFilePaths.size() + m_includeFilePaths.size();
|
||||
}
|
||||
|
||||
size_t FileRegister::getParsedFilesCount() const
|
||||
{
|
||||
return getFilesCount() - getUnparsedSourceFilePaths().size() - getUnparsedIncludeFilePaths().size();
|
||||
}
|
||||
|
||||
@@ -12,19 +12,25 @@ class FileManager;
|
||||
class FileRegister
|
||||
{
|
||||
public:
|
||||
FileRegister(const FileManager* fileManager, const std::vector<FilePath>& filePaths);
|
||||
explicit FileRegister(const FileManager* fileManager);
|
||||
|
||||
const FileManager* getFileManager() const;
|
||||
|
||||
const std::vector<FilePath>& getSourceFilePaths() const;
|
||||
void setFilePaths(const std::vector<FilePath>& filePaths);
|
||||
|
||||
std::vector<FilePath> getUnparsedSourceFilePaths() const;
|
||||
std::vector<FilePath> getUnparsedIncludeFilePaths() const;
|
||||
|
||||
bool includeFileIsParsing(const FilePath& filePath) const;
|
||||
bool includeFileIsParsed(const FilePath& filePath) const;
|
||||
|
||||
void markSourceFileParsed(const std::string& filePath);
|
||||
void markIncludeFileParsing(const std::string& filePath);
|
||||
void markParsingIncludeFilesParsed();
|
||||
|
||||
size_t getFilesCount() const;
|
||||
size_t getParsedFilesCount() const;
|
||||
|
||||
private:
|
||||
enum ParseState
|
||||
{
|
||||
@@ -33,9 +39,11 @@ private:
|
||||
STATE_PARSED
|
||||
};
|
||||
|
||||
std::vector<FilePath> getUnparsedFilePaths(const std::map<FilePath, ParseState> filePaths) const;
|
||||
|
||||
const FileManager* m_fileManager;
|
||||
|
||||
std::vector<FilePath> m_sourceFilePaths;
|
||||
std::map<FilePath, ParseState> m_sourceFilePaths;
|
||||
std::map<FilePath, ParseState> m_includeFilePaths;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
class MessageFinishedParsing: public Message<MessageFinishedParsing>
|
||||
{
|
||||
public:
|
||||
MessageFinishedParsing(size_t fileCount, float parseTime, size_t errorCount)
|
||||
MessageFinishedParsing(size_t fileCount, size_t totalFileCount, float parseTime, size_t errorCount)
|
||||
: fileCount(fileCount)
|
||||
, totalFileCount(totalFileCount)
|
||||
, parseTime(parseTime)
|
||||
, errorCount(errorCount)
|
||||
{
|
||||
@@ -19,6 +20,7 @@ public:
|
||||
}
|
||||
|
||||
size_t fileCount;
|
||||
size_t totalFileCount;
|
||||
float parseTime;
|
||||
size_t errorCount;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef MESSAGE_INTERRUPT_TASKS_H
|
||||
#define MESSAGE_INTERRUPT_TASKS_H
|
||||
|
||||
#include "utility/messaging/Message.h"
|
||||
|
||||
class MessageInterruptTasks:
|
||||
public Message<MessageInterruptTasks>
|
||||
{
|
||||
public:
|
||||
MessageInterruptTasks()
|
||||
{
|
||||
}
|
||||
|
||||
static const std::string getStaticType()
|
||||
{
|
||||
return "MessageInterruptTasks";
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MESSAGE_INTERRUPT_TASKS_H
|
||||
@@ -0,0 +1,89 @@
|
||||
#include "utility/scheduling/Task.h"
|
||||
|
||||
#include "utility/logging/logging.h"
|
||||
#include "utility/scheduling/TaskScheduler.h"
|
||||
|
||||
void Task::dispatch(std::shared_ptr<Task> task)
|
||||
{
|
||||
TaskScheduler::getInstance()->pushTask(task);
|
||||
}
|
||||
|
||||
Task::Task()
|
||||
: m_state(STATE_NEW)
|
||||
{
|
||||
}
|
||||
|
||||
Task::~Task()
|
||||
{
|
||||
}
|
||||
|
||||
Task::TaskState Task::getState() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
Task::TaskState Task::process(bool interruptTask)
|
||||
{
|
||||
if (interruptTask)
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case STATE_NEW:
|
||||
case STATE_CANCELED:
|
||||
break;
|
||||
case STATE_RUNNING:
|
||||
interrupt();
|
||||
exit();
|
||||
break;
|
||||
case STATE_FINISHED:
|
||||
revert();
|
||||
break;
|
||||
}
|
||||
|
||||
setState(STATE_CANCELED);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case STATE_NEW:
|
||||
case STATE_CANCELED:
|
||||
enter();
|
||||
case STATE_RUNNING:
|
||||
{
|
||||
TaskState newState = update();
|
||||
if (newState == STATE_NEW || newState == STATE_CANCELED)
|
||||
{
|
||||
LOG_ERROR("Task can't change to state NEW or CANCELLED");
|
||||
return m_state;
|
||||
}
|
||||
|
||||
setState(newState);
|
||||
if (m_state == STATE_FINISHED)
|
||||
{
|
||||
exit();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATE_FINISHED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return m_state;
|
||||
}
|
||||
|
||||
void Task::execute()
|
||||
{
|
||||
TaskState state;
|
||||
do
|
||||
{
|
||||
state = process(false);
|
||||
}
|
||||
while (state != STATE_FINISHED);
|
||||
}
|
||||
|
||||
void Task::setState(TaskState state)
|
||||
{
|
||||
m_state = state;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef TASK_H
|
||||
#define TASK_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
class Task
|
||||
{
|
||||
public:
|
||||
enum TaskState
|
||||
{
|
||||
STATE_NEW,
|
||||
STATE_RUNNING,
|
||||
STATE_FINISHED,
|
||||
STATE_CANCELED
|
||||
};
|
||||
|
||||
static void dispatch(std::shared_ptr<Task> task);
|
||||
|
||||
Task();
|
||||
virtual ~Task();
|
||||
|
||||
TaskState getState() const;
|
||||
|
||||
TaskState process(bool interruptTask);
|
||||
void execute();
|
||||
|
||||
virtual void enter() = 0;
|
||||
virtual TaskState update() = 0;
|
||||
virtual void exit() = 0;
|
||||
|
||||
virtual void interrupt() = 0;
|
||||
virtual void revert() = 0;
|
||||
|
||||
protected:
|
||||
void setState(TaskState state);
|
||||
|
||||
private:
|
||||
TaskState m_state;
|
||||
};
|
||||
|
||||
#endif // TASK_H
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "utility/scheduling/TaskGroup.h"
|
||||
|
||||
TaskGroup::TaskGroup()
|
||||
{
|
||||
}
|
||||
|
||||
TaskGroup::~TaskGroup()
|
||||
{
|
||||
}
|
||||
|
||||
void TaskGroup::addTask(std::shared_ptr<Task> task)
|
||||
{
|
||||
m_tasks.push_back(task);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef TASK_GROUP_H
|
||||
#define TASK_GROUP_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "utility/scheduling/Task.h"
|
||||
|
||||
class TaskGroup
|
||||
: public Task
|
||||
{
|
||||
public:
|
||||
TaskGroup();
|
||||
virtual ~TaskGroup();
|
||||
|
||||
void addTask(std::shared_ptr<Task> task);
|
||||
|
||||
protected:
|
||||
std::vector<std::shared_ptr<Task>> m_tasks;
|
||||
};
|
||||
|
||||
#endif // TASK_GROUP_H
|
||||
@@ -0,0 +1,61 @@
|
||||
#include "utility/scheduling/TaskGroupSequential.h"
|
||||
|
||||
TaskGroupSequential::TaskGroupSequential()
|
||||
: m_taskIndex(-1)
|
||||
{
|
||||
}
|
||||
|
||||
TaskGroupSequential::~TaskGroupSequential()
|
||||
{
|
||||
}
|
||||
|
||||
void TaskGroupSequential::enter()
|
||||
{
|
||||
}
|
||||
|
||||
Task::TaskState TaskGroupSequential::update()
|
||||
{
|
||||
if (!m_tasks.size())
|
||||
{
|
||||
return Task::STATE_FINISHED;
|
||||
}
|
||||
|
||||
if (m_taskIndex < 0 || m_tasks[m_taskIndex]->getState() != Task::STATE_RUNNING)
|
||||
{
|
||||
m_taskIndex++;
|
||||
}
|
||||
|
||||
std::shared_ptr<Task> task = m_tasks[m_taskIndex];
|
||||
|
||||
TaskState state = task->process(false);
|
||||
|
||||
if (state == Task::STATE_FINISHED && size_t(m_taskIndex + 1) == m_tasks.size())
|
||||
{
|
||||
return Task::STATE_FINISHED;
|
||||
}
|
||||
|
||||
return Task::STATE_RUNNING;
|
||||
}
|
||||
|
||||
void TaskGroupSequential::exit()
|
||||
{
|
||||
}
|
||||
|
||||
void TaskGroupSequential::interrupt()
|
||||
{
|
||||
if (m_taskIndex > 0 && size_t(m_taskIndex) < m_tasks.size())
|
||||
{
|
||||
for (int i = m_taskIndex; i >= 0; i--)
|
||||
{
|
||||
m_tasks[m_taskIndex]->process(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TaskGroupSequential::revert()
|
||||
{
|
||||
for (int i = m_tasks.size() - 1; i >= 0; i--)
|
||||
{
|
||||
m_tasks[m_taskIndex]->process(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef TASK_GROUP_SEQUENTIAL_H
|
||||
#define TASK_GROUP_SEQUENTIAL_H
|
||||
|
||||
#include "utility/scheduling/TaskGroup.h"
|
||||
|
||||
class TaskGroupSequential
|
||||
: public TaskGroup
|
||||
{
|
||||
public:
|
||||
TaskGroupSequential();
|
||||
virtual ~TaskGroupSequential();
|
||||
|
||||
virtual void enter();
|
||||
virtual TaskState update();
|
||||
virtual void exit();
|
||||
|
||||
virtual void interrupt();
|
||||
virtual void revert();
|
||||
|
||||
private:
|
||||
int m_taskIndex;
|
||||
};
|
||||
|
||||
#endif // TASK_GROUP_SEQUENTIAL_H
|
||||
@@ -0,0 +1,132 @@
|
||||
#include "utility/scheduling/TaskScheduler.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "utility/logging/logging.h"
|
||||
#include "utility/messaging/type/MessageStatus.h"
|
||||
|
||||
std::shared_ptr<TaskScheduler> TaskScheduler::getInstance()
|
||||
{
|
||||
if (!s_instance)
|
||||
{
|
||||
s_instance = std::shared_ptr<TaskScheduler>(new TaskScheduler());
|
||||
}
|
||||
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
void TaskScheduler::pushTask(std::shared_ptr<Task> task)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_tasksMutex);
|
||||
m_tasks.push(task);
|
||||
}
|
||||
|
||||
void TaskScheduler::interruptCurrentTask()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_tasksMutex);
|
||||
m_interruptTask = true;
|
||||
}
|
||||
|
||||
void TaskScheduler::startSchedulerLoopThreaded()
|
||||
{
|
||||
std::thread(&TaskScheduler::startSchedulerLoop, this).detach();
|
||||
}
|
||||
|
||||
void TaskScheduler::startSchedulerLoop()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_loopMutex);
|
||||
|
||||
if (m_loopIsRunning)
|
||||
{
|
||||
LOG_ERROR("Loop is already running");
|
||||
return;
|
||||
}
|
||||
|
||||
m_loopIsRunning = true;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_loopMutex);
|
||||
|
||||
if (!m_loopIsRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
updateTasks();
|
||||
|
||||
const int SLEEP_TIME_MS = 25;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_MS));
|
||||
}
|
||||
}
|
||||
|
||||
void TaskScheduler::stopSchedulerLoop()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_loopMutex);
|
||||
|
||||
if (!m_loopIsRunning)
|
||||
{
|
||||
LOG_WARNING("Loop is not running");
|
||||
}
|
||||
|
||||
m_loopIsRunning = false;
|
||||
}
|
||||
|
||||
interruptCurrentTask();
|
||||
}
|
||||
|
||||
bool TaskScheduler::loopIsRunning() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_loopMutex);
|
||||
return m_loopIsRunning;
|
||||
}
|
||||
|
||||
std::shared_ptr<TaskScheduler> TaskScheduler::s_instance;
|
||||
|
||||
TaskScheduler::TaskScheduler()
|
||||
: m_loopIsRunning(false)
|
||||
, m_interruptTask(false)
|
||||
{
|
||||
}
|
||||
|
||||
void TaskScheduler::updateTasks()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_tasksMutex);
|
||||
|
||||
bool interrupt = m_interruptTask;
|
||||
|
||||
while (m_tasks.size())
|
||||
{
|
||||
std::shared_ptr<Task> task = m_tasks.front();
|
||||
|
||||
m_tasksMutex.unlock();
|
||||
Task::TaskState state = task->process(interrupt);
|
||||
m_tasksMutex.lock();
|
||||
|
||||
if (state == Task::STATE_FINISHED || state == Task::STATE_CANCELED)
|
||||
{
|
||||
m_tasks.pop();
|
||||
}
|
||||
|
||||
interrupt = m_interruptTask;
|
||||
}
|
||||
|
||||
m_interruptTask = false;
|
||||
}
|
||||
|
||||
void TaskScheduler::handleMessage(MessageInterruptTasks* message)
|
||||
{
|
||||
interruptCurrentTask();
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_tasksMutex);
|
||||
if (m_tasks.size())
|
||||
{
|
||||
MessageStatus("Stop running tasks...").dispatch();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef TASK_SCHEDULER_H
|
||||
#define TASK_SCHEDULER_H
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include "utility/messaging/MessageListener.h"
|
||||
#include "utility/messaging/type/MessageInterruptTasks.h"
|
||||
#include "utility/scheduling/Task.h"
|
||||
|
||||
class TaskScheduler
|
||||
: public MessageListener<MessageInterruptTasks>
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<TaskScheduler> getInstance();
|
||||
|
||||
void pushTask(std::shared_ptr<Task> task);
|
||||
void interruptCurrentTask();
|
||||
|
||||
void startSchedulerLoopThreaded();
|
||||
void startSchedulerLoop();
|
||||
void stopSchedulerLoop();
|
||||
|
||||
bool loopIsRunning() const;
|
||||
|
||||
private:
|
||||
static std::shared_ptr<TaskScheduler> s_instance;
|
||||
|
||||
TaskScheduler();
|
||||
TaskScheduler(const TaskScheduler&);
|
||||
void operator=(const TaskScheduler&);
|
||||
|
||||
void updateTasks();
|
||||
|
||||
virtual void handleMessage(MessageInterruptTasks* message);
|
||||
|
||||
bool m_loopIsRunning;
|
||||
|
||||
std::queue<std::shared_ptr<Task>> m_tasks;
|
||||
bool m_interruptTask;
|
||||
|
||||
mutable std::mutex m_tasksMutex;
|
||||
mutable std::mutex m_loopMutex;
|
||||
};
|
||||
|
||||
#endif // TASK_SCHEDULER_H
|
||||
@@ -1,16 +1,26 @@
|
||||
#include "utility/utility.h"
|
||||
|
||||
float utility::duration(std::function<void()> func)
|
||||
utility::TimePoint utility::durationStart()
|
||||
{
|
||||
std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now();
|
||||
|
||||
func();
|
||||
return std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
float utility::duration(const TimePoint& start)
|
||||
{
|
||||
std::chrono::duration<float> duration =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start);
|
||||
return duration.count();
|
||||
}
|
||||
|
||||
float utility::duration(std::function<void()> func)
|
||||
{
|
||||
const TimePoint start = durationStart();
|
||||
|
||||
func();
|
||||
|
||||
return duration(start);
|
||||
}
|
||||
|
||||
bool utility::intersectionPoint(Vec2f a1, Vec2f b1, Vec2f a2, Vec2f b2, Vec2f* i)
|
||||
{
|
||||
Vec2f p = a1;
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
namespace utility
|
||||
{
|
||||
typedef std::chrono::time_point<std::chrono::system_clock> TimePoint;
|
||||
|
||||
TimePoint durationStart();
|
||||
float duration(const TimePoint& start);
|
||||
float duration(std::function<void()> func);
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -2405,7 +2405,7 @@ public:
|
||||
TS_ASSERT_EQUALS(client.usages.size(), 3);
|
||||
TS_ASSERT_EQUALS(client.typeUses.size(), 8);
|
||||
|
||||
TS_ASSERT_EQUALS(client.files.size(), 2);
|
||||
TS_ASSERT_EQUALS(client.files.size(), 3);
|
||||
TS_ASSERT_EQUALS(client.includes.size(), 1);
|
||||
}
|
||||
|
||||
@@ -2429,6 +2429,11 @@ private:
|
||||
errors.push_back(addLocationSuffix(message, location));
|
||||
}
|
||||
|
||||
virtual size_t getErrorCount() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual Id onTypedefParsed(
|
||||
const ParseLocation& location, const NameHierarchy& nameHierarchy, const ParseTypeUsage& underlyingType,
|
||||
AccessType access
|
||||
|
||||
Reference in New Issue
Block a user