Commit 8bbad430 authored by Tobias Hunger's avatar Tobias Hunger
Browse files

OutputParser: Allow to flush pending tasks.



Add a way to flush out tasks from the outputparsers. This is necessary
to make parsers that keep state more robust.

Flush parsers (once) before adding any new task. This keeps the sequence
intact.

Flush all parsers once the parsing is done to make sure there is no task
queued somewhere.

Task-number: QTCREATORBUG-9195
Change-Id: Icd37df1f470cb73123ad286d6900ad1047a1d512
Reviewed-by: default avatarTobias Hunger <tobias.hunger@digia.com>
parent 14763118
......@@ -88,7 +88,7 @@ using namespace ProjectExplorer;
AbstractProcessStep::AbstractProcessStep(BuildStepList *bsl, const Core::Id id) :
BuildStep(bsl, id), m_timer(0), m_futureInterface(0),
m_ignoreReturnValue(false), m_process(0),
m_outputParserChain(0)
m_outputParserChain(0), m_skipFlush(false)
{
}
......@@ -96,7 +96,7 @@ AbstractProcessStep::AbstractProcessStep(BuildStepList *bsl,
AbstractProcessStep *bs) :
BuildStep(bsl, bs), m_timer(0), m_futureInterface(0),
m_ignoreReturnValue(bs->m_ignoreReturnValue),
m_process(0), m_outputParserChain(0)
m_process(0), m_outputParserChain(0), m_skipFlush(false)
{
}
......@@ -261,6 +261,9 @@ void AbstractProcessStep::processStarted()
void AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus status)
{
if (m_outputParserChain)
m_outputParserChain->flush();
QString command = QDir::toNativeSeparators(m_param.effectiveCommand());
if (status == QProcess::NormalExit && exitCode == 0) {
emit addOutput(tr("The process \"%1\" exited normally.").arg(command),
......@@ -367,6 +370,13 @@ void AbstractProcessStep::taskAdded(const ProjectExplorer::Task &task)
if (m_ignoreReturnValue)
return;
// flush out any pending tasks before proceeding:
if (!m_skipFlush && m_outputParserChain) {
m_skipFlush = true;
m_outputParserChain->flush();
m_skipFlush = false;
}
Task editable(task);
QString filePath = task.file.toString();
if (!filePath.isEmpty() && !QDir::isAbsolutePath(filePath)) {
......
......@@ -101,6 +101,7 @@ private:
QEventLoop *m_eventLoop;
ProjectExplorer::IOutputParser *m_outputParserChain;
bool m_killProcess;
bool m_skipFlush;
};
} // namespace ProjectExplorer
......
......@@ -52,7 +52,7 @@ void ClangParser::stdError(const QString &line)
{
const QString lne = rightTrimmed(line);
if (m_summaryRegExp.indexIn(lne) > -1) {
emitTask();
doFlush();
m_expectSnippet = false;
return;
}
......@@ -74,11 +74,11 @@ void ClangParser::stdError(const QString &line)
if (m_inLineRegExp.indexIn(lne) > -1) {
m_expectSnippet = true;
newTask(Task::Unknown,
lne.trimmed(),
Utils::FileName::fromUserInput(m_inLineRegExp.cap(2)), /* filename */
m_inLineRegExp.cap(3).toInt(), /* line */
Core::Id(Constants::TASK_CATEGORY_COMPILE));
newTask(Task(Task::Unknown,
lne.trimmed(),
Utils::FileName::fromUserInput(m_inLineRegExp.cap(2)), /* filename */
m_inLineRegExp.cap(3).toInt(), /* line */
Core::Id(Constants::TASK_CATEGORY_COMPILE)));
return;
}
......
......@@ -60,11 +60,6 @@ GccParser::GccParser()
appendOutputParser(new LdParser);
}
GccParser::~GccParser()
{
emitTask();
}
void GccParser::stdError(const QString &line)
{
QString lne = rightTrimmed(line);
......@@ -79,11 +74,11 @@ void GccParser::stdError(const QString &line)
// Handle misc issues:
if (lne.startsWith(QLatin1String("ERROR:")) ||
lne == QLatin1String("* cpp failed")) {
newTask(Task::Error,
lne /* description */,
Utils::FileName() /* filename */,
-1 /* linenumber */,
Core::Id(Constants::TASK_CATEGORY_COMPILE));
newTask(Task(Task::Error,
lne /* description */,
Utils::FileName() /* filename */,
-1 /* linenumber */,
Core::Id(Constants::TASK_CATEGORY_COMPILE)));
return;
} else if (m_regExpGccNames.indexIn(lne) > -1) {
QString description = lne.mid(m_regExpGccNames.matchedLength());
......@@ -121,44 +116,40 @@ void GccParser::stdError(const QString &line)
newTask(task);
return;
} else if (m_regExpIncluded.indexIn(lne) > -1) {
newTask(Task::Unknown,
lne.trimmed() /* description */,
Utils::FileName::fromUserInput(m_regExpIncluded.cap(1)) /* filename */,
m_regExpIncluded.cap(3).toInt() /* linenumber */,
Core::Id(Constants::TASK_CATEGORY_COMPILE));
newTask(Task(Task::Unknown,
lne.trimmed() /* description */,
Utils::FileName::fromUserInput(m_regExpIncluded.cap(1)) /* filename */,
m_regExpIncluded.cap(3).toInt() /* linenumber */,
Core::Id(Constants::TASK_CATEGORY_COMPILE)));
return;
} else if (lne.startsWith(QLatin1Char(' '))) {
amendDescription(lne, true);
return;
}
emitTask();
doFlush();
IOutputParser::stdError(line);
}
void GccParser::stdOutput(const QString &line)
{
emitTask();
doFlush();
IOutputParser::stdOutput(line);
}
void GccParser::newTask(const Task &task)
{
emitTask();
doFlush();
m_currentTask = task;
}
void GccParser::newTask(Task::TaskType type_, const QString &description_,
const Utils::FileName &file_, int line_, const Core::Id &category_)
{
newTask(Task(type_, description_, file_, line_, category_));
}
void GccParser::emitTask()
void GccParser::doFlush()
{
if (!m_currentTask.isNull())
emit addTask(m_currentTask);
m_currentTask = Task();
if (m_currentTask.isNull())
return;
Task t = m_currentTask;
m_currentTask.clear();
emit addTask(t);
}
void GccParser::amendDescription(const QString &desc, bool monospaced)
......
......@@ -44,15 +44,13 @@ class GccParser : public ProjectExplorer::IOutputParser
public:
GccParser();
~GccParser();
void stdError(const QString &line);
void stdOutput(const QString &line);
protected:
void newTask(const Task &task);
void newTask(Task::TaskType type_, const QString &description_,
const Utils::FileName &file_, int line_, const Core::Id &category_);
void emitTask();
void doFlush();
void amendDescription(const QString &desc, bool monospaced);
......
......@@ -90,11 +90,11 @@ void GnuMakeParser::stdError(const QString &line)
++m_fatalErrorCount;
if (!m_suppressIssues) {
m_suppressIssues = true;
addTask(Task(Task::Error,
m_makefileError.cap(3),
Utils::FileName::fromUserInput(m_makefileError.cap(1)),
m_makefileError.cap(2).toInt(),
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
emit addTask(Task(Task::Error,
m_makefileError.cap(3),
Utils::FileName::fromUserInput(m_makefileError.cap(1)),
m_makefileError.cap(2).toInt(),
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
}
return;
}
......@@ -110,10 +110,10 @@ void GnuMakeParser::stdError(const QString &line)
type = Task::Warning;
}
addTask(Task(type, description,
Utils::FileName() /* filename */,
-1, /* line */
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
emit addTask(Task(type, description,
Utils::FileName() /* filename */,
-1, /* line */
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
}
return;
}
......
......@@ -108,6 +108,17 @@
This method can be overwritten to change the task.
*/
/*!
\fn void ProjectExplorer::IOutputParser::doFlush()
\brief This method is called whenever a parser is supposed to flush his state.
Parsers may have state (e.g. because they need to aggregate several lines into one task). This
method is called when this state needs to be flushed out to be visible.
doFlush() is called by flush(). flush() is called on childparsers whenever a new task is added.
It is also called once when all input has been parsed.
*/
namespace ProjectExplorer {
IOutputParser::IOutputParser() : m_parser(0)
......@@ -180,6 +191,9 @@ void IOutputParser::taskAdded(const ProjectExplorer::Task &task)
emit addTask(task);
}
void IOutputParser::doFlush()
{ }
bool IOutputParser::hasFatalErrors() const
{
return false || (m_parser && m_parser->hasFatalErrors());
......@@ -191,6 +205,13 @@ void IOutputParser::setWorkingDirectory(const QString &workingDirectory)
m_parser->setWorkingDirectory(workingDirectory);
}
void IOutputParser::flush()
{
doFlush();
if (m_parser)
m_parser->flush();
}
QString IOutputParser::rightTrimmed(const QString &in)
{
int pos = in.length();
......
......@@ -44,7 +44,7 @@ class PROJECTEXPLORER_EXPORT IOutputParser : public QObject
Q_OBJECT
public:
IOutputParser();
virtual ~IOutputParser();
~IOutputParser();
virtual void appendOutputParser(IOutputParser *parser);
......@@ -60,6 +60,8 @@ public:
// For GnuMakeParser
virtual void setWorkingDirectory(const QString &workingDirectory);
void flush(); // flush out pending tasks
static QString rightTrimmed(const QString &in);
signals:
......@@ -71,6 +73,8 @@ public slots:
virtual void taskAdded(const ProjectExplorer::Task &task);
private:
virtual void doFlush();
IOutputParser *m_parser;
};
......
......@@ -58,12 +58,6 @@ LinuxIccParser::LinuxIccParser()
appendOutputParser(new LdParser);
}
LinuxIccParser::~LinuxIccParser()
{
if (!m_temporary.isNull())
addTask(m_temporary);
}
void LinuxIccParser::stdError(const QString &line)
{
if (m_expectFirstLine && m_firstLine.indexIn(line) != -1) {
......@@ -107,6 +101,15 @@ void LinuxIccParser::stdError(const QString &line)
}
}
void LinuxIccParser::doFlush()
{
if (m_temporary.isNull())
return;
Task t = m_temporary;
m_temporary.clear();
emit addTask(t);
}
#ifdef WITH_TESTS
# include <QTest>
# include "projectexplorer.h"
......
......@@ -43,11 +43,12 @@ class LinuxIccParser : public ProjectExplorer::IOutputParser
public:
LinuxIccParser();
~LinuxIccParser();
void stdError(const QString &line);
private:
void doFlush();
QRegExp m_firstLine;
QRegExp m_continuationLines;
QRegExp m_caretLine;
......
......@@ -69,11 +69,6 @@ MsvcParser::MsvcParser()
m_additionalInfoRegExp.setMinimal(true);
}
MsvcParser::~MsvcParser()
{
sendQueuedTask();
}
void MsvcParser::stdOutput(const QString &line)
{
int infoPos = m_additionalInfoRegExp.indexIn(line);
......@@ -141,7 +136,7 @@ void MsvcParser::stdError(const QString &line)
bool MsvcParser::processCompileLine(const QString &line)
{
sendQueuedTask();
doFlush();
if (m_compileRegExp.indexIn(line) > -1) {
QPair<Utils::FileName, int> position = parseFileName( m_compileRegExp.cap(1));
......@@ -159,13 +154,14 @@ bool MsvcParser::processCompileLine(const QString &line)
return false;
}
void MsvcParser::sendQueuedTask()
void MsvcParser::doFlush()
{
if (m_lastTask.isNull())
return;
addTask(m_lastTask);
m_lastTask = Task();
Task t = m_lastTask;
m_lastTask.clear();
emit addTask(t);
}
// Unit tests:
......
......@@ -44,14 +44,12 @@ class MsvcParser : public ProjectExplorer::IOutputParser
public:
MsvcParser();
~MsvcParser();
void stdOutput(const QString &line);
void stdError(const QString &line);
void flush();
private:
void sendQueuedTask();
void doFlush();
bool processCompileLine(const QString &line);
QRegExp m_compileRegExp;
......
......@@ -58,6 +58,7 @@ void OutputParserTester::testParsing(const QString &lines,
else
childParser()->stdError(input + QLatin1Char('\n'));
}
childParser()->flush();
// first disconnect ourselves from the end of the parser chain again
IOutputParser * parser = this;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment