aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2020-04-08 17:45:39 +0200
committerChristian Kandeler <christian.kandeler@qt.io>2020-04-09 14:49:32 +0000
commit45ba9fcd535e4cfd5f057149b1ca4bb4dfed5bdb (patch)
tree3e3246ccf3d971e69004182007bd1b726b88b8bf /src/plugins
parentfa517bd72aa21ea82072af27ce98030c4ff028f2 (diff)
Output parsers: Replace the chaining approach
Use "flat" aggregation instead. This is another step towards the formatter/parser merger. Along the way, also fix some some subclasses (mostly in BareMetal) that erroneously forwarded handled output to other parsers. Task-number: QTCREATORBUG-22665 Change-Id: I12947349ca663d2e6bbfc99efd069d69e2b54969 Reviewed-by: hjk <hjk@qt.io>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/android/androidpackageinstallationstep.cpp4
-rw-r--r--src/plugins/android/javaparser.cpp56
-rw-r--r--src/plugins/android/javaparser.h3
-rw-r--r--src/plugins/baremetal/iarewparser.cpp107
-rw-r--r--src/plugins/baremetal/iarewparser.h4
-rw-r--r--src/plugins/baremetal/iarewtoolchain.cpp4
-rw-r--r--src/plugins/baremetal/iarewtoolchain.h2
-rw-r--r--src/plugins/baremetal/keilparser.cpp156
-rw-r--r--src/plugins/baremetal/keilparser.h4
-rw-r--r--src/plugins/baremetal/keiltoolchain.cpp4
-rw-r--r--src/plugins/baremetal/keiltoolchain.h2
-rw-r--r--src/plugins/baremetal/sdccparser.cpp55
-rw-r--r--src/plugins/baremetal/sdccparser.h4
-rw-r--r--src/plugins/baremetal/sdcctoolchain.cpp4
-rw-r--r--src/plugins/baremetal/sdcctoolchain.h2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildstep.cpp4
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeparser.cpp41
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeparser.h2
-rw-r--r--src/plugins/ios/iosbuildstep.cpp4
-rw-r--r--src/plugins/ios/iosdsymbuildstep.cpp5
-rw-r--r--src/plugins/nim/project/nimblebuildstep.cpp17
-rw-r--r--src/plugins/nim/project/nimcompilerbuildstep.cpp25
-rw-r--r--src/plugins/nim/project/nimtoolchain.cpp4
-rw-r--r--src/plugins/nim/project/nimtoolchain.h2
-rw-r--r--src/plugins/projectexplorer/abstractprocessstep.cpp47
-rw-r--r--src/plugins/projectexplorer/abstractprocessstep.h1
-rw-r--r--src/plugins/projectexplorer/clangparser.cpp30
-rw-r--r--src/plugins/projectexplorer/clangparser.h4
-rw-r--r--src/plugins/projectexplorer/customparser.cpp8
-rw-r--r--src/plugins/projectexplorer/customparser.h2
-rw-r--r--src/plugins/projectexplorer/customtoolchain.cpp14
-rw-r--r--src/plugins/projectexplorer/customtoolchain.h2
-rw-r--r--src/plugins/projectexplorer/gccparser.cpp133
-rw-r--r--src/plugins/projectexplorer/gccparser.h7
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.cpp12
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.h6
-rw-r--r--src/plugins/projectexplorer/gnumakeparser.cpp72
-rw-r--r--src/plugins/projectexplorer/gnumakeparser.h5
-rw-r--r--src/plugins/projectexplorer/ioutputparser.cpp193
-rw-r--r--src/plugins/projectexplorer/ioutputparser.h32
-rw-r--r--src/plugins/projectexplorer/kit.cpp8
-rw-r--r--src/plugins/projectexplorer/kit.h2
-rw-r--r--src/plugins/projectexplorer/kitinformation.cpp7
-rw-r--r--src/plugins/projectexplorer/kitinformation.h2
-rw-r--r--src/plugins/projectexplorer/kitmanager.cpp4
-rw-r--r--src/plugins/projectexplorer/kitmanager.h2
-rw-r--r--src/plugins/projectexplorer/ldparser.cpp32
-rw-r--r--src/plugins/projectexplorer/ldparser.h2
-rw-r--r--src/plugins/projectexplorer/linuxiccparser.cpp42
-rw-r--r--src/plugins/projectexplorer/linuxiccparser.h4
-rw-r--r--src/plugins/projectexplorer/lldparser.cpp15
-rw-r--r--src/plugins/projectexplorer/lldparser.h2
-rw-r--r--src/plugins/projectexplorer/makestep.cpp4
-rw-r--r--src/plugins/projectexplorer/msvcparser.cpp174
-rw-r--r--src/plugins/projectexplorer/msvcparser.h9
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.cpp8
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.h4
-rw-r--r--src/plugins/projectexplorer/osparser.cpp49
-rw-r--r--src/plugins/projectexplorer/osparser.h7
-rw-r--r--src/plugins/projectexplorer/outputparser_test.cpp16
-rw-r--r--src/plugins/projectexplorer/outputparser_test.h3
-rw-r--r--src/plugins/projectexplorer/parseissuesdialog.cpp6
-rw-r--r--src/plugins/projectexplorer/processstep.cpp2
-rw-r--r--src/plugins/projectexplorer/toolchain.h2
-rw-r--r--src/plugins/projectexplorer/toolchainsettingsaccessor.cpp2
-rw-r--r--src/plugins/projectexplorer/xcodebuildparser.cpp76
-rw-r--r--src/plugins/projectexplorer/xcodebuildparser.h8
-rw-r--r--src/plugins/qbsprojectmanager/qbsbuildstep.cpp6
-rw-r--r--src/plugins/qmakeprojectmanager/qmakemakestep.cpp22
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeparser.cpp18
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeparser.h2
-rw-r--r--src/plugins/qtsupport/qtkitinformation.cpp11
-rw-r--r--src/plugins/qtsupport/qtkitinformation.h2
-rw-r--r--src/plugins/qtsupport/qtparser.cpp17
-rw-r--r--src/plugins/qtsupport/qtparser.h2
-rw-r--r--src/plugins/qtsupport/qttestparser.cpp22
-rw-r--r--src/plugins/qtsupport/qttestparser.h2
77 files changed, 777 insertions, 902 deletions
diff --git a/src/plugins/android/androidpackageinstallationstep.cpp b/src/plugins/android/androidpackageinstallationstep.cpp
index 3c61a32915..9fd25e9296 100644
--- a/src/plugins/android/androidpackageinstallationstep.cpp
+++ b/src/plugins/android/androidpackageinstallationstep.cpp
@@ -112,9 +112,7 @@ bool AndroidPackageInstallationStep::init()
pp->setCommandLine(cmd);
setOutputParser(new GnuMakeParser());
- IOutputParser *parser = target()->kit()->createOutputParser();
- if (parser)
- appendOutputParser(parser);
+ appendOutputParsers(target()->kit()->createOutputParsers());
outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
m_androidDirsToClean.clear();
diff --git a/src/plugins/android/javaparser.cpp b/src/plugins/android/javaparser.cpp
index 1f45263675..8be5f08b82 100644
--- a/src/plugins/android/javaparser.cpp
+++ b/src/plugins/android/javaparser.cpp
@@ -51,39 +51,33 @@ void JavaParser::setSourceDirectory(const Utils::FilePath &sourceDirectory)
m_sourceDirectory = sourceDirectory;
}
-void JavaParser::handleLine(const QString &line, Utils::OutputFormat type)
+IOutputParser::Status JavaParser::doHandleLine(const QString &line, Utils::OutputFormat type)
{
- parse(line);
- IOutputParser::handleLine(line, type);
-}
-
-void JavaParser::parse(const QString &line)
-{
- if (m_javaRegExp.indexIn(line) > -1) {
- bool ok;
- int lineno = m_javaRegExp.cap(3).toInt(&ok);
- if (!ok)
- lineno = -1;
- Utils::FilePath file = Utils::FilePath::fromUserInput(m_javaRegExp.cap(2));
- if (file.isChildOf(m_buildDirectory)) {
- Utils::FilePath relativePath = file.relativeChildPath(m_buildDirectory);
- file = m_sourceDirectory.pathAppended(relativePath.toString());
- }
+ Q_UNUSED(type);
+ if (m_javaRegExp.indexIn(line) == -1)
+ return Status::NotHandled;
- if (file.toFileInfo().isRelative()) {
- for (int i = 0; i < m_fileList.size(); i++)
- if (m_fileList[i].endsWith(file.toString())) {
- file = Utils::FilePath::fromString(m_fileList[i]);
- break;
- }
- }
-
- CompileTask task(Task::Error,
- m_javaRegExp.cap(4).trimmed(),
- absoluteFilePath(file),
- lineno);
- emit addTask(task, 1);
- return;
+ bool ok;
+ int lineno = m_javaRegExp.cap(3).toInt(&ok);
+ if (!ok)
+ lineno = -1;
+ Utils::FilePath file = Utils::FilePath::fromUserInput(m_javaRegExp.cap(2));
+ if (file.isChildOf(m_buildDirectory)) {
+ Utils::FilePath relativePath = file.relativeChildPath(m_buildDirectory);
+ file = m_sourceDirectory.pathAppended(relativePath.toString());
+ }
+ if (file.toFileInfo().isRelative()) {
+ for (int i = 0; i < m_fileList.size(); i++)
+ if (m_fileList[i].endsWith(file.toString())) {
+ file = Utils::FilePath::fromString(m_fileList[i]);
+ break;
+ }
}
+ CompileTask task(Task::Error,
+ m_javaRegExp.cap(4).trimmed(),
+ absoluteFilePath(file),
+ lineno);
+ emit addTask(task, 1);
+ return Status::Done;
}
diff --git a/src/plugins/android/javaparser.h b/src/plugins/android/javaparser.h
index ad4ebdc8c5..160006636c 100644
--- a/src/plugins/android/javaparser.h
+++ b/src/plugins/android/javaparser.h
@@ -45,8 +45,7 @@ public:
void setSourceDirectory(const Utils::FilePath &sourceDirectory);
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
- void parse(const QString &line);
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
QRegExp m_javaRegExp;
QStringList m_fileList;
diff --git a/src/plugins/baremetal/iarewparser.cpp b/src/plugins/baremetal/iarewparser.cpp
index 39a8a112f1..f3e357544d 100644
--- a/src/plugins/baremetal/iarewparser.cpp
+++ b/src/plugins/baremetal/iarewparser.cpp
@@ -190,67 +190,56 @@ bool IarParser::parseErrorMessage1(const QString &lne)
return true;
}
-void IarParser::handleLine(const QString &line, OutputFormat type)
+IOutputParser::Status IarParser::doHandleLine(const QString &line, OutputFormat type)
{
- if (type == StdOutFormat)
- stdOutput(line);
- else
- stdError(line);
-}
-
-void IarParser::stdError(const QString &line)
-{
- IOutputParser::handleLine(line, StdErrFormat);
-
const QString lne = rightTrimmed(line);
+ if (type == StdOutFormat) {
+ // The call sequence has the meaning!
+ const bool leastOneParsed = parseErrorInCommandLineMessage(lne)
+ || parseErrorMessage1(lne);
+ if (!leastOneParsed) {
+ doFlush();
+ return Status::NotHandled;
+ }
+ return Status::InProgress;
+ }
if (parseErrorOrFatalErrorDetailsMessage1(lne))
- return;
+ return Status::InProgress;
if (parseErrorOrFatalErrorDetailsMessage2(lne))
- return;
+ return Status::InProgress;
if (parseWarningOrErrorOrFatalErrorDetailsMessage1(lne))
- return;
+ return Status::InProgress;
- if (lne.isEmpty()) {
- //
- } else if (!lne.startsWith(' ')) {
- return;
- } else if (m_expectFilePath) {
+ if (m_expectFilePath) {
if (lne.endsWith(']')) {
const QString lastPart = lne.left(lne.size() - 1);
m_filePathParts.push_back(lastPart);
+ doFlush();
+ return Status::Done;
} else {
m_filePathParts.push_back(lne);
- return;
+ return Status::InProgress;
}
- } else if (m_expectSnippet) {
+ }
+ if (m_expectSnippet && lne.startsWith(' ')) {
if (!lne.endsWith("Fatal error detected, aborting.")) {
m_snippets.push_back(lne);
- return;
+ return Status::InProgress;
}
} else if (m_expectDescription) {
if (!lne.startsWith(" ")) {
m_descriptionParts.push_back(lne.trimmed());
- return;
+ return Status::InProgress;
}
}
- doFlush();
-}
-
-void IarParser::stdOutput(const QString &line)
-{
- IOutputParser::handleLine(line, StdOutFormat);
-
- const QString lne = rightTrimmed(line);
-
- // The call sequence has the meaning!
- const bool leastOneParsed = parseErrorInCommandLineMessage(lne)
- || parseErrorMessage1(lne);
- if (!leastOneParsed)
- return;
+ if (!m_lastTask.isNull()) {
+ doFlush();
+ return Status::Done;
+ }
- doFlush();
+ return Status::NotHandled;
}
void IarParser::doFlush()
@@ -308,7 +297,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
QTest::newRow("Error in command line")
<< QString::fromLatin1("Error in command line: Some error")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("Error in command line: Some error\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"Error in command line: Some error"))
@@ -317,7 +306,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
QTest::newRow("Linker error")
<< QString::fromLatin1("Error[e46]: Some error")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("Error[e46]: Some error\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"[e46]: Some error"))
@@ -329,8 +318,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
" Some warning \"foo\" bar")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\",63 Warning[Pe223]:\n"
- " Some warning \"foo\" bar\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"[Pe223]: Some warning \"foo\" bar",
Utils::FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -344,10 +332,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
" Some warning")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1(" some_detail;\n"
- " ^\n"
- "\"c:\\foo\\main.c\",63 Warning[Pe223]:\n"
- " Some warning\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"[Pe223]: Some warning\n"
" some_detail;\n"
@@ -362,9 +347,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
" , split")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\",63 Warning[Pe223]:\n"
- " Some warning\n"
- " , split\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"[Pe223]: Some warning, split",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -376,8 +359,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
" Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\",63 Error[Pe223]:\n"
- " Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"[Pe223]: Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -391,10 +373,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
" Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1(" some_detail;\n"
- " ^\n"
- "\"c:\\foo\\main.c\",63 Error[Pe223]:\n"
- " Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"[Pe223]: Some error\n"
" some_detail;\n"
@@ -409,9 +388,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
" , split")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\",63 Error[Pe223]:\n"
- " Some error\n"
- " , split\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"[Pe223]: Some error, split",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -425,10 +402,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
"]")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("Error[Li005]: Some error \"foo\" [referenced from c:\\fo\n"
- " o\\bar\\mai\n"
- " n.c.o\n"
- "]\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"[Li005]: Some error \"foo\"",
FilePath::fromUserInput("c:\\foo\\bar\\main.c.o")))
@@ -441,10 +415,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
"Fatal error detected, aborting.")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("Fatal error[Su011]: Some error:\n"
- " c:\\foo.c\n"
- " c:\\bar.c\n"
- "Fatal error detected, aborting.\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"[Su011]: Some error:\n"
" c:\\foo.c\n"
@@ -455,7 +426,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
<< QString::fromLatin1("At end of source Error[Pe040]: Some error \";\"")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("At end of source Error[Pe040]: Some error \";\"\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"[Pe040]: Some error \";\""))
<< QString();
@@ -464,7 +435,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
void BareMetalPlugin::testIarOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new IarParser);
+ testbench.addLineParser(new IarParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/baremetal/iarewparser.h b/src/plugins/baremetal/iarewparser.h
index 0b066a5f33..546bb400fc 100644
--- a/src/plugins/baremetal/iarewparser.h
+++ b/src/plugins/baremetal/iarewparser.h
@@ -52,9 +52,7 @@ private:
bool parseErrorInCommandLineMessage(const QString &lne);
bool parseErrorMessage1(const QString &lne);
- void handleLine(const QString &line, Utils::OutputFormat type) final;
- void stdError(const QString &line);
- void stdOutput(const QString &line);
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) final;
void doFlush() final;
ProjectExplorer::Task m_lastTask;
diff --git a/src/plugins/baremetal/iarewtoolchain.cpp b/src/plugins/baremetal/iarewtoolchain.cpp
index a67ba48eda..34afc316ef 100644
--- a/src/plugins/baremetal/iarewtoolchain.cpp
+++ b/src/plugins/baremetal/iarewtoolchain.cpp
@@ -354,9 +354,9 @@ void IarToolChain::addToEnvironment(Environment &env) const
}
}
-IOutputParser *IarToolChain::outputParser() const
+QList<IOutputParser *> IarToolChain::outputParsers() const
{
- return new IarParser;
+ return {new IarParser()};
}
QVariantMap IarToolChain::toMap() const
diff --git a/src/plugins/baremetal/iarewtoolchain.h b/src/plugins/baremetal/iarewtoolchain.h
index 59a67e02ef..932e8555a7 100644
--- a/src/plugins/baremetal/iarewtoolchain.h
+++ b/src/plugins/baremetal/iarewtoolchain.h
@@ -68,7 +68,7 @@ public:
const Utils::FilePath &,
const Utils::Environment &env) const final;
void addToEnvironment(Utils::Environment &env) const final;
- ProjectExplorer::IOutputParser *outputParser() const final;
+ QList<ProjectExplorer::IOutputParser *> outputParsers() const final;
QVariantMap toMap() const final;
bool fromMap(const QVariantMap &data) final;
diff --git a/src/plugins/baremetal/keilparser.cpp b/src/plugins/baremetal/keilparser.cpp
index acd6491f6e..f02ff16bde 100644
--- a/src/plugins/baremetal/keilparser.cpp
+++ b/src/plugins/baremetal/keilparser.cpp
@@ -190,34 +190,6 @@ bool KeilParser::parseMcs51FatalErrorMessage2(const QString &lne)
return true;
}
-void KeilParser::handleLine(const QString &line, OutputFormat type)
-{
- if (type == StdOutFormat)
- stdOutput(line);
- else
- stdError(line);
-}
-
-void KeilParser::stdError(const QString &line)
-{
- IOutputParser::handleLine(line, StdErrFormat);
-
- const QString lne = rightTrimmed(line);
-
- // Check for ARM compiler specific patterns.
- if (parseArmWarningOrErrorDetailsMessage(lne))
- return;
- if (parseArmErrorOrFatalErorrMessage(lne))
- return;
-
- if (lne.startsWith(' ')) {
- m_snippets.push_back(lne);
- return;
- }
-
- doFlush();
-}
-
static bool hasDetailsEntry(const QString &trimmedLine)
{
const QRegularExpression re("^([0-9A-F]{4})");
@@ -234,46 +206,59 @@ static bool hasDetailsPointer(const QString &trimmedLine)
return trimmedLine.contains('_');
}
-void KeilParser::stdOutput(const QString &line)
+IOutputParser::Status KeilParser::doHandleLine(const QString &line, OutputFormat type)
{
- IOutputParser::handleLine(line, StdOutFormat);
-
QString lne = rightTrimmed(line);
-
- // Check for MSC51 compiler specific patterns.
- const bool parsed = parseMcs51WarningOrErrorDetailsMessage1(lne)
- || parseMcs51WarningOrErrorDetailsMessage2(lne);
- if (!parsed) {
+ if (type == StdOutFormat) {
+ // Check for MSC51 compiler specific patterns.
+ const bool parsed = parseMcs51WarningOrErrorDetailsMessage1(lne)
+ || parseMcs51WarningOrErrorDetailsMessage2(lne);
+ if (parsed)
+ return Status::InProgress;
if (parseMcs51WarningOrFatalErrorMessage(lne))
- return;
+ return Status::InProgress;
if (parseMcs51FatalErrorMessage2(lne))
- return;
+ return Status::InProgress;
+
+ if (m_lastTask.isNull()) {
+ // Check for details, which are comes on a previous
+ // lines, before the message.
+
+ // This code handles the details in a form like:
+ // 0000 24 ljmp usb_stub_isr ; (00) Setup data available.
+ // *** _____________________________________^
+ // 003C 54 ljmp usb_stub_isr ; (3C) EP8 in/out.
+ // *** _____________________________________^
+ if (hasDetailsEntry(lne) || hasDetailsPointer(lne)) {
+ lne.replace(0, 4, " ");
+ m_snippets.push_back(lne);
+ return Status::InProgress;
+ }
+ } else {
+ // Check for details, which are comes on a next
+ // lines, after the message.
+ if (lne.startsWith(' ')) {
+ m_snippets.push_back(lne);
+ return Status::InProgress;
+ }
+ }
+ doFlush();
+ return Status::NotHandled;
}
- if (m_lastTask.isNull()) {
- // Check for details, which are comes on a previous
- // lines, before the message.
-
- // This code handles the details in a form like:
- // 0000 24 ljmp usb_stub_isr ; (00) Setup data available.
- // *** _____________________________________^
- // 003C 54 ljmp usb_stub_isr ; (3C) EP8 in/out.
- // *** _____________________________________^
- if (hasDetailsEntry(lne) || hasDetailsPointer(lne)) {
- lne.replace(0, 4, " ");
- m_snippets.push_back(lne);
- return;
- }
- } else {
- // Check for details, which are comes on a next
- // lines, after the message.
- if (lne.startsWith(' ')) {
- m_snippets.push_back(lne);
- return;
- }
+ // Check for ARM compiler specific patterns.
+ if (parseArmWarningOrErrorDetailsMessage(lne))
+ return Status::InProgress;
+ if (parseArmErrorOrFatalErorrMessage(lne))
+ return Status::InProgress;
+
+ if (lne.startsWith(' ')) {
+ m_snippets.push_back(lne);
+ return Status::InProgress;
}
doFlush();
+ return Status::NotHandled;
}
void KeilParser::doFlush()
@@ -328,7 +313,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
<< QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Warning: #1234: Some warning")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Warning: #1234: Some warning\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"#1234: Some warning",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -341,9 +326,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
" ^")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Warning: #1234: Some warning\n"
- " int f;\n"
- " ^\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"#1234: Some warning\n"
" int f;\n"
@@ -356,7 +339,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
<< QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Error: #1234: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Error: #1234: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"#1234: Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -367,7 +350,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
<< QString::fromLatin1("\"flash.sct\", line 51 (column 20): Error: L1234: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"flash.sct\", line 51 (column 20): Error: L1234: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"L1234: Some error",
FilePath::fromUserInput("flash.sct"),
@@ -380,9 +363,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
" ^")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Error: #1234: Some error\n"
- " int f;\n"
- " ^\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"#1234: Some error\n"
" int f;\n"
@@ -395,7 +376,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
<< QString::fromLatin1("\"c:\\foo\\main.c\", line 71: Error: At end of source: #40: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\", line 71: Error: At end of source: #40: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"#40: Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -406,7 +387,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
<< QString::fromLatin1("Error: L6226E: Some error.")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("Error: L6226E: Some error.\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"L6226E: Some error."))
<< QString();
@@ -417,7 +398,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Assembler simple warning")
<< QString::fromLatin1("*** WARNING #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some warning")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** WARNING #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some warning\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Warning,
"#A9: Some warning",
@@ -428,7 +409,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Assembler simple error")
<< QString::fromLatin1("*** ERROR #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some error")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** ERROR #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some error\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"#A9: Some error",
@@ -441,9 +422,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
" Some detail 1\n"
" Some detail N")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("A51 FATAL ERROR -\n"
- " Some detail 1\n"
- " Some detail N\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"Assembler fatal error\n"
@@ -456,9 +435,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
"*** ___^\n"
"*** ERROR #A45 IN 28 (d:\\foo.a51, LINE 28): Some error")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("01AF Some detail\n"
- "*** ___^\n"
- "*** ERROR #A45 IN 28 (d:\\foo.a51, LINE 28): Some error\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"#A45: Some error\n"
@@ -472,7 +449,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Compiler simple warning")
<< QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Warning,
"C123: Some warning",
@@ -483,7 +460,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Compiler extended warning")
<< QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning : 'extended text'")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning : 'extended text'\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Warning,
"C123: Some warning : 'extended text'",
@@ -494,7 +471,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Compiler simple error")
<< QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"C123: Some error",
@@ -505,7 +482,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Compiler extended error")
<< QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error : 'extended text'")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error : 'extended text'\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"C123: Some error : 'extended text'",
@@ -518,9 +495,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
" Some detail 1\n"
" Some detail N")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("C51 FATAL-ERROR -\n"
- " Some detail 1\n"
- " Some detail N\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"Compiler fatal error\n"
@@ -533,8 +508,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
<< QString::fromLatin1("*** WARNING L16: Some warning\n"
" Some detail 1")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** WARNING L16: Some warning\n"
- " Some detail 1\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Warning,
"L16: Some warning\n"
@@ -544,7 +518,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Linker simple fatal error")
<< QString::fromLatin1("*** FATAL ERROR L456: Some error")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** FATAL ERROR L456: Some error\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"L456: Some error"))
@@ -555,9 +529,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
" Some detail 1\n"
" Some detail N")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** FATAL ERROR L456: Some error\n"
- " Some detail 1\n"
- " Some detail N\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"L456: Some error\n"
@@ -569,7 +541,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
void BareMetalPlugin::testKeilOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new KeilParser);
+ testbench.addLineParser(new KeilParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/baremetal/keilparser.h b/src/plugins/baremetal/keilparser.h
index d2bcba9f85..3fff04bb09 100644
--- a/src/plugins/baremetal/keilparser.h
+++ b/src/plugins/baremetal/keilparser.h
@@ -55,9 +55,7 @@ private:
bool parseMcs51WarningOrFatalErrorMessage(const QString &lne);
bool parseMcs51FatalErrorMessage2(const QString &lne);
- void handleLine(const QString &line, Utils::OutputFormat type) final;
- void stdError(const QString &line);
- void stdOutput(const QString &line);
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) final;
void doFlush() final;
ProjectExplorer::Task m_lastTask;
diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp
index fd05815cd5..96ee6ec0f8 100644
--- a/src/plugins/baremetal/keiltoolchain.cpp
+++ b/src/plugins/baremetal/keiltoolchain.cpp
@@ -374,9 +374,9 @@ void KeilToolChain::addToEnvironment(Environment &env) const
}
}
-IOutputParser *KeilToolChain::outputParser() const
+QList<IOutputParser *> KeilToolChain::outputParsers() const
{
- return new KeilParser;
+ return {new KeilParser};
}
QVariantMap KeilToolChain::toMap() const
diff --git a/src/plugins/baremetal/keiltoolchain.h b/src/plugins/baremetal/keiltoolchain.h
index 341e28a1b3..7326973037 100644
--- a/src/plugins/baremetal/keiltoolchain.h
+++ b/src/plugins/baremetal/keiltoolchain.h
@@ -69,7 +69,7 @@ public:
const Utils::FilePath &,
const Utils::Environment &env) const final;
void addToEnvironment(Utils::Environment &env) const final;
- ProjectExplorer::IOutputParser *outputParser() const final;
+ QList<ProjectExplorer::IOutputParser *> outputParsers() const final;
QVariantMap toMap() const final;
bool fromMap(const QVariantMap &data) final;
diff --git a/src/plugins/baremetal/sdccparser.cpp b/src/plugins/baremetal/sdccparser.cpp
index 445758c49c..fdf46c3349 100644
--- a/src/plugins/baremetal/sdccparser.cpp
+++ b/src/plugins/baremetal/sdccparser.cpp
@@ -87,17 +87,10 @@ void SdccParser::amendDescription(const QString &desc)
++m_lines;
}
-void SdccParser::handleLine(const QString &line, OutputFormat type)
+IOutputParser::Status SdccParser::doHandleLine(const QString &line, OutputFormat type)
{
if (type == StdOutFormat)
- stdOutput(line);
- else
- stdError(line);
-}
-
-void SdccParser::stdError(const QString &line)
-{
- IOutputParser::handleLine(line, StdErrFormat);
+ return Status::NotHandled;
const QString lne = rightTrimmed(line);
@@ -115,7 +108,7 @@ void SdccParser::stdError(const QString &line)
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
const QString descr = match.captured(MessageTextIndex);
newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
- return;
+ return Status::InProgress;
}
re.setPattern("^(.+\\.\\S+):(\\d+): (Error|error|syntax error): (.+)$");
@@ -129,7 +122,7 @@ void SdccParser::stdError(const QString &line)
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
const QString descr = match.captured(MessageTextIndex);
newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
- return;
+ return Status::InProgress;
}
re.setPattern("^at (\\d+): (warning|error) \\d+: (.+)$");
@@ -139,7 +132,7 @@ void SdccParser::stdError(const QString &line)
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
const QString descr = match.captured(MessageTextIndex);
newTask(CompileTask(type, descr));
- return;
+ return Status::InProgress;
}
re.setPattern("^\\?ASlink-(Warning|Error)-(.+)$");
@@ -149,20 +142,16 @@ void SdccParser::stdError(const QString &line)
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
const QString descr = match.captured(MessageTextIndex);
newTask(CompileTask(type, descr));
- return;
+ return Status::InProgress;
}
if (!m_lastTask.isNull()) {
amendDescription(lne);
- return;
+ return Status::InProgress;
}
doFlush();
-}
-
-void SdccParser::stdOutput(const QString &line)
-{
- IOutputParser::handleLine(line, StdOutFormat);
+ return Status::NotHandled;
}
void SdccParser::doFlush()
@@ -215,7 +204,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("c:\\foo\\main.c:63: Error: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: Error: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -226,7 +215,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("c:\\foo\\main.c:63: warning 123: Some warning")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: warning 123: Some warning\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"Some warning",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -239,9 +228,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
" details #2")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: warning 123: Some warning\n"
- "details #1\n"
- " details #2\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"Some warning\n"
"details #1\n"
@@ -254,7 +241,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("c:\\foo\\main.c:63: error: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: error: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -265,7 +252,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("c:\\foo\\main.c:63: error 123: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: error 123: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -278,9 +265,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
" details #2")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: error 123: Some error\n"
- "details #1\n"
- " details #2\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"Some error\n"
"details #1\n"
@@ -293,7 +278,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("c:\\foo\\main.c:63: syntax error: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: syntax error: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -304,7 +289,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("at 1: error 123: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("at 1: error 123: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"Some error"))
<< QString();
@@ -313,7 +298,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("at 1: warning 123: Some warning")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("at 1: warning 123: Some warning\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"Some warning"))
<< QString();
@@ -322,7 +307,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("?ASlink-Warning-Couldn't find library 'foo.lib'")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("?ASlink-Warning-Couldn't find library 'foo.lib'\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"Couldn't find library 'foo.lib'"))
<< QString();
@@ -331,7 +316,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("?ASlink-Error-<cannot open> : \"foo.rel\"")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("?ASlink-Error-<cannot open> : \"foo.rel\"\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"<cannot open> : \"foo.rel\""))
<< QString();
@@ -340,7 +325,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
void BareMetalPlugin::testSdccOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new SdccParser);
+ testbench.addLineParser(new SdccParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/baremetal/sdccparser.h b/src/plugins/baremetal/sdccparser.h
index 2ce08e0d97..f96b00a3b5 100644
--- a/src/plugins/baremetal/sdccparser.h
+++ b/src/plugins/baremetal/sdccparser.h
@@ -45,9 +45,7 @@ private:
void newTask(const ProjectExplorer::Task &task);
void amendDescription(const QString &desc);
- void handleLine(const QString &line, Utils::OutputFormat type) final;
- void stdError(const QString &line);
- void stdOutput(const QString &line);
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) final;
void doFlush() final;
ProjectExplorer::Task m_lastTask;
diff --git a/src/plugins/baremetal/sdcctoolchain.cpp b/src/plugins/baremetal/sdcctoolchain.cpp
index 84dd4134c7..fcdf639e89 100644
--- a/src/plugins/baremetal/sdcctoolchain.cpp
+++ b/src/plugins/baremetal/sdcctoolchain.cpp
@@ -307,9 +307,9 @@ void SdccToolChain::addToEnvironment(Environment &env) const
}
}
-IOutputParser *SdccToolChain::outputParser() const
+QList<IOutputParser *> SdccToolChain::outputParsers() const
{
- return new SdccParser;
+ return {new SdccParser};
}
QVariantMap SdccToolChain::toMap() const
diff --git a/src/plugins/baremetal/sdcctoolchain.h b/src/plugins/baremetal/sdcctoolchain.h
index aff4be1226..01e3abbe54 100644
--- a/src/plugins/baremetal/sdcctoolchain.h
+++ b/src/plugins/baremetal/sdcctoolchain.h
@@ -69,7 +69,7 @@ public:
const Utils::FilePath &,
const Utils::Environment &env) const final;
void addToEnvironment(Utils::Environment &env) const final;
- ProjectExplorer::IOutputParser *outputParser() const final;
+ QList<ProjectExplorer::IOutputParser *> outputParsers() const final;
QVariantMap toMap() const final;
bool fromMap(const QVariantMap &data) final;
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
index 519433e894..22b114518b 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
@@ -214,9 +214,7 @@ bool CMakeBuildStep::init()
cmakeParser->setSourceDirectory(projectDirectory.toString());
setOutputParser(cmakeParser);
appendOutputParser(new GnuMakeParser);
- IOutputParser *parser = target()->kit()->createOutputParser();
- if (parser)
- appendOutputParser(parser);
+ appendOutputParsers(target()->kit()->createOutputParsers());
outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
return AbstractProcessStep::init();
diff --git a/src/plugins/cmakeprojectmanager/cmakeparser.cpp b/src/plugins/cmakeprojectmanager/cmakeparser.cpp
index 69283d421b..86d369cd60 100644
--- a/src/plugins/cmakeprojectmanager/cmakeparser.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeparser.cpp
@@ -57,22 +57,21 @@ void CMakeParser::setSourceDirectory(const QString &sourceDir)
m_sourceDirectory = QDir(sourceDir);
}
-void CMakeParser::handleLine(const QString &line, OutputFormat type)
+IOutputParser::Status CMakeParser::doHandleLine(const QString &line, OutputFormat type)
{
- if (type != StdErrFormat) {
- IOutputParser::handleLine(line, type);
- return;
- }
+ if (type != StdErrFormat)
+ return Status::NotHandled;
QString trimmedLine = rightTrimmed(line);
switch (m_expectTripleLineErrorData) {
case NONE:
if (trimmedLine.isEmpty() && !m_lastTask.isNull()) {
- if (m_skippedFirstEmptyLine)
+ if (m_skippedFirstEmptyLine) {
doFlush();
- else
- m_skippedFirstEmptyLine = true;
- return;
+ return Status::InProgress;
+ }
+ m_skippedFirstEmptyLine = true;
+ return Status::InProgress;
}
if (m_skippedFirstEmptyLine)
m_skippedFirstEmptyLine = false;
@@ -87,35 +86,34 @@ void CMakeParser::handleLine(const QString &line, OutputFormat type)
absoluteFilePath(FilePath::fromUserInput(path)),
m_commonError.cap(2).toInt());
m_lines = 1;
- return;
+ return Status::InProgress;
} else if (m_nextSubError.indexIn(trimmedLine) != -1) {
m_lastTask = BuildSystemTask(Task::Error, QString(),
absoluteFilePath(FilePath::fromUserInput(m_nextSubError.cap(1))));
m_lines = 1;
- return;
+ return Status::InProgress;
} else if (trimmedLine.startsWith(QLatin1String(" ")) && !m_lastTask.isNull()) {
if (!m_lastTask.description.isEmpty())
m_lastTask.description.append(QLatin1Char(' '));
m_lastTask.description.append(trimmedLine.trimmed());
++m_lines;
- return;
+ return Status::InProgress;
} else if (trimmedLine.endsWith(QLatin1String("in cmake code at"))) {
m_expectTripleLineErrorData = LINE_LOCATION;
doFlush();
const Task::TaskType type =
trimmedLine.contains(QLatin1String("Error")) ? Task::Error : Task::Warning;
m_lastTask = BuildSystemTask(type, QString());
- return;
+ return Status::InProgress;
} else if (trimmedLine.startsWith("CMake Error: ")) {
m_lastTask = BuildSystemTask(Task::Error, trimmedLine.mid(13));
m_lines = 1;
- return;
+ return Status::InProgress;
} else if (trimmedLine.startsWith("-- ") || trimmedLine.startsWith(" * ")) {
// Do not pass on lines starting with "-- " or "* ". Those are typical CMake output
- return;
+ return Status::InProgress;
}
- IOutputParser::handleLine(line, StdErrFormat);
- return;
+ return Status::NotHandled;
case LINE_LOCATION:
{
QRegularExpressionMatch m = m_locationLine.match(trimmedLine);
@@ -124,7 +122,7 @@ void CMakeParser::handleLine(const QString &line, OutputFormat type)
m_lastTask.line = m.captured(1).toInt();
m_expectTripleLineErrorData = LINE_DESCRIPTION;
}
- return;
+ return Status::InProgress;
case LINE_DESCRIPTION:
m_lastTask.description = trimmedLine;
if (trimmedLine.endsWith(QLatin1Char('\"')))
@@ -132,14 +130,15 @@ void CMakeParser::handleLine(const QString &line, OutputFormat type)
else {
m_expectTripleLineErrorData = NONE;
doFlush();
+ return Status::Done;
}
- return;
+ return Status::InProgress;
case LINE_DESCRIPTION2:
m_lastTask.description.append(QLatin1Char('\n'));
m_lastTask.description.append(trimmedLine);
m_expectTripleLineErrorData = NONE;
doFlush();
- return;
+ return Status::Done;
}
}
@@ -301,7 +300,7 @@ void Internal::CMakeProjectPlugin::testCMakeParser_data()
void Internal::CMakeProjectPlugin::testCMakeParser()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new CMakeParser);
+ testbench.addLineParser(new CMakeParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/cmakeprojectmanager/cmakeparser.h b/src/plugins/cmakeprojectmanager/cmakeparser.h
index a8fc2298d4..4b17b5a62f 100644
--- a/src/plugins/cmakeprojectmanager/cmakeparser.h
+++ b/src/plugins/cmakeprojectmanager/cmakeparser.h
@@ -45,7 +45,7 @@ public:
void setSourceDirectory(const QString &sourceDir);
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
void doFlush() override;
enum TripleLineError { NONE, LINE_LOCATION, LINE_DESCRIPTION, LINE_DESCRIPTION2 };
diff --git a/src/plugins/ios/iosbuildstep.cpp b/src/plugins/ios/iosbuildstep.cpp
index 6566134398..a8503d0fc6 100644
--- a/src/plugins/ios/iosbuildstep.cpp
+++ b/src/plugins/ios/iosbuildstep.cpp
@@ -223,9 +223,7 @@ bool IosBuildStep::init()
setIgnoreReturnValue(m_clean);
setOutputParser(new GnuMakeParser());
- IOutputParser *parser = target()->kit()->createOutputParser();
- if (parser)
- appendOutputParser(parser);
+ appendOutputParsers(target()->kit()->createOutputParsers());
outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
return AbstractProcessStep::init();
diff --git a/src/plugins/ios/iosdsymbuildstep.cpp b/src/plugins/ios/iosdsymbuildstep.cpp
index 937811bcd3..f188630bc6 100644
--- a/src/plugins/ios/iosdsymbuildstep.cpp
+++ b/src/plugins/ios/iosdsymbuildstep.cpp
@@ -80,9 +80,8 @@ bool IosDsymBuildStep::init()
// That is mostly so that rebuild works on an already clean project
setIgnoreReturnValue(m_clean);
- setOutputParser(target()->kit()->createOutputParser());
- if (outputParser())
- outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
+ appendOutputParsers(target()->kit()->createOutputParsers());
+ outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
return AbstractProcessStep::init();
}
diff --git a/src/plugins/nim/project/nimblebuildstep.cpp b/src/plugins/nim/project/nimblebuildstep.cpp
index eb7a31f07a..36efa46313 100644
--- a/src/plugins/nim/project/nimblebuildstep.cpp
+++ b/src/plugins/nim/project/nimblebuildstep.cpp
@@ -45,15 +45,9 @@ namespace {
class NimParser : public IOutputParser
{
-private:
- void handleLine(const QString &line, Utils::OutputFormat type) override
- {
- parseLine(line.trimmed());
- IOutputParser::handleLine(line, type);
- }
-
- void parseLine(const QString &line)
+ Status doHandleLine(const QString &lne, Utils::OutputFormat) override
{
+ const QString line = lne.trimmed();
static QRegularExpression regex("(.+.nim)\\((\\d+), (\\d+)\\) (.+)",
QRegularExpression::OptimizeOnFirstUsageOption);
static QRegularExpression warning("(Warning):(.*)",
@@ -63,13 +57,13 @@ private:
QRegularExpressionMatch match = regex.match(line);
if (!match.hasMatch())
- return;
+ return Status::NotHandled;
const QString filename = match.captured(1);
bool lineOk = false;
const int lineNumber = match.captured(2).toInt(&lineOk);
const QString message = match.captured(4);
if (!lineOk)
- return;
+ return Status::NotHandled;
Task::TaskType type = Task::Unknown;
@@ -78,10 +72,11 @@ private:
else if (error.match(message).hasMatch())
type = Task::Error;
else
- return;
+ return Status::NotHandled;
emit addTask(CompileTask(type, message, absoluteFilePath(FilePath::fromUserInput(filename)),
lineNumber));
+ return Status::Done;
}
};
diff --git a/src/plugins/nim/project/nimcompilerbuildstep.cpp b/src/plugins/nim/project/nimcompilerbuildstep.cpp
index 071bc85cb2..8bdf39d576 100644
--- a/src/plugins/nim/project/nimcompilerbuildstep.cpp
+++ b/src/plugins/nim/project/nimcompilerbuildstep.cpp
@@ -47,14 +47,9 @@ namespace Nim {
class NimParser : public ProjectExplorer::IOutputParser
{
- void handleLine(const QString &line, Utils::OutputFormat type) override
- {
- parseLine(line.trimmed());
- IOutputParser::handleLine(line, type);
- }
-
- void parseLine(const QString &line)
+ Status doHandleLine(const QString &lne, Utils::OutputFormat) override
{
+ const QString line = lne.trimmed();
static QRegularExpression regex("(.+.nim)\\((\\d+), (\\d+)\\) (.+)",
QRegularExpression::OptimizeOnFirstUsageOption);
static QRegularExpression warning("(Warning):(.*)",
@@ -64,13 +59,13 @@ class NimParser : public ProjectExplorer::IOutputParser
QRegularExpressionMatch match = regex.match(line);
if (!match.hasMatch())
- return;
+ return Status::NotHandled;
const QString filename = match.captured(1);
bool lineOk = false;
const int lineNumber = match.captured(2).toInt(&lineOk);
const QString message = match.captured(4);
if (!lineOk)
- return;
+ return Status::NotHandled;
Task::TaskType type = Task::Unknown;
@@ -79,10 +74,11 @@ class NimParser : public ProjectExplorer::IOutputParser
else if (error.match(message).hasMatch())
type = Task::Error;
else
- return;
+ return Status::NotHandled;
emit addTask(CompileTask(type, message, absoluteFilePath(FilePath::fromUserInput(filename)),
lineNumber));
+ return Status::Done;
}
};
@@ -107,8 +103,7 @@ NimCompilerBuildStep::NimCompilerBuildStep(BuildStepList *parentList, Core::Id i
bool NimCompilerBuildStep::init()
{
setOutputParser(new NimParser());
- if (IOutputParser *parser = target()->kit()->createOutputParser())
- appendOutputParser(parser);
+ appendOutputParsers(target()->kit()->createOutputParsers());
outputParser()->addSearchDir(processParameters()->effectiveWorkingDirectory());
return AbstractProcessStep::init();
}
@@ -308,7 +303,7 @@ void NimPlugin::testNimParser_data()
QTest::newRow("Parse error string")
<< QString::fromLatin1("main.nim(23, 1) Error: undeclared identifier: 'x'")
<< OutputParserTester::STDERR
- << QString("") << QString("main.nim(23, 1) Error: undeclared identifier: 'x'\n")
+ << QString() << QString()
<< Tasks({CompileTask(Task::Error,
"Error: undeclared identifier: 'x'",
FilePath::fromUserInput("main.nim"), 23)})
@@ -317,7 +312,7 @@ void NimPlugin::testNimParser_data()
QTest::newRow("Parse warning string")
<< QString::fromLatin1("lib/pure/parseopt.nim(56, 34) Warning: quoteIfContainsWhite is deprecated [Deprecated]")
<< OutputParserTester::STDERR
- << QString("") << QString("lib/pure/parseopt.nim(56, 34) Warning: quoteIfContainsWhite is deprecated [Deprecated]\n")
+ << QString() << QString()
<< Tasks({CompileTask(Task::Warning,
"Warning: quoteIfContainsWhite is deprecated [Deprecated]",
FilePath::fromUserInput("lib/pure/parseopt.nim"), 56)})
@@ -327,7 +322,7 @@ void NimPlugin::testNimParser_data()
void NimPlugin::testNimParser()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new NimParser);
+ testbench.addLineParser(new NimParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/nim/project/nimtoolchain.cpp b/src/plugins/nim/project/nimtoolchain.cpp
index 031557c889..7aed9dacf6 100644
--- a/src/plugins/nim/project/nimtoolchain.cpp
+++ b/src/plugins/nim/project/nimtoolchain.cpp
@@ -120,9 +120,9 @@ void NimToolChain::setCompilerCommand(const FilePath &compilerCommand)
parseVersion(compilerCommand, m_version);
}
-IOutputParser *NimToolChain::outputParser() const
+QList<IOutputParser *> NimToolChain::outputParsers() const
{
- return nullptr;
+ return {};
}
std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> NimToolChain::createConfigurationWidget()
diff --git a/src/plugins/nim/project/nimtoolchain.h b/src/plugins/nim/project/nimtoolchain.h
index a140f1444f..df21587776 100644
--- a/src/plugins/nim/project/nimtoolchain.h
+++ b/src/plugins/nim/project/nimtoolchain.h
@@ -56,7 +56,7 @@ public:
Utils::FilePath compilerCommand() const final;
QString compilerVersion() const;
void setCompilerCommand(const Utils::FilePath &compilerCommand);
- ProjectExplorer::IOutputParser *outputParser() const final;
+ QList<ProjectExplorer::IOutputParser *> outputParsers() const final;
std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() final;
QVariantMap toMap() const final;
diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp
index fce8f47818..3a2ed067bf 100644
--- a/src/plugins/projectexplorer/abstractprocessstep.cpp
+++ b/src/plugins/projectexplorer/abstractprocessstep.cpp
@@ -106,11 +106,10 @@ public:
AbstractProcessStep *q;
std::unique_ptr<Utils::QtcProcess> m_process;
- std::unique_ptr<IOutputParser> m_outputParserChain;
+ IOutputParser m_outputParser;
ProcessParameters m_param;
Utils::FileInProjectFinder m_fileFinder;
bool m_ignoreReturnValue = false;
- bool m_skipFlush = false;
bool m_lowPriority = false;
std::unique_ptr<QTextDecoder> stdoutStream;
std::unique_ptr<QTextDecoder> stderrStream;
@@ -120,6 +119,8 @@ AbstractProcessStep::AbstractProcessStep(BuildStepList *bsl, Core::Id id) :
BuildStep(bsl, id),
d(new Private(this))
{
+ connect(&d->m_outputParser, &IOutputParser::addTask,
+ this, &AbstractProcessStep::taskAdded);
}
AbstractProcessStep::~AbstractProcessStep()
@@ -130,16 +131,10 @@ AbstractProcessStep::~AbstractProcessStep()
/*!
Deletes all existing output parsers and starts a new chain with the
given parser.
-
- Derived classes need to call this function.
*/
-
void AbstractProcessStep::setOutputParser(IOutputParser *parser)
{
- parser->addFilter(&Internal::filterAnsiEscapeCodes);
- d->m_outputParserChain.reset(parser);
- connect(d->m_outputParserChain.get(), &IOutputParser::addTask,
- this, &AbstractProcessStep::taskAdded);
+ d->m_outputParser.setLineParsers({parser});
}
/*!
@@ -149,14 +144,18 @@ void AbstractProcessStep::appendOutputParser(IOutputParser *parser)
{
if (!parser)
return;
+ d->m_outputParser.addLineParser(parser);
+}
- QTC_ASSERT(d->m_outputParserChain, return);
- d->m_outputParserChain->appendOutputParser(parser);
+void AbstractProcessStep::appendOutputParsers(const QList<IOutputParser *> &parsers)
+{
+ for (IOutputParser * const p : parsers)
+ appendOutputParser(p);
}
IOutputParser *AbstractProcessStep::outputParser() const
{
- return d->m_outputParserChain.get();
+ return &d->m_outputParser;
}
void AbstractProcessStep::emitFaultyConfigurationMessage()
@@ -189,6 +188,7 @@ void AbstractProcessStep::setIgnoreReturnValue(bool b)
bool AbstractProcessStep::init()
{
+ d->m_outputParser.addFilter(&Internal::filterAnsiEscapeCodes);
d->m_fileFinder.setProjectDirectory(project()->projectDirectory());
d->m_fileFinder.setProjectFiles(project()->files(Project::AllFiles));
return !d->m_process;
@@ -244,7 +244,7 @@ void AbstractProcessStep::doRun()
if (!d->m_process->waitForStarted()) {
processStartupFailed();
d->m_process.reset();
- d->m_outputParserChain.reset();
+ d->m_outputParser.clear();
finish(false);
return;
}
@@ -272,7 +272,7 @@ void AbstractProcessStep::cleanUp(QProcess *process)
processFinished(process->exitCode(), process->exitStatus());
const bool returnValue = processSucceeded(process->exitCode(), process->exitStatus()) || d->m_ignoreReturnValue;
- d->m_outputParserChain.reset();
+ d->m_outputParser.clear();
d->m_process.reset();
// Report result
@@ -302,8 +302,8 @@ void AbstractProcessStep::processStarted()
void AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus status)
{
- if (d->m_outputParserChain)
- d->m_outputParserChain->flush();
+ d->m_outputParser.flush();
+ d->m_outputParser.clear();
QString command = QDir::toNativeSeparators(d->m_param.effectiveCommand().toString());
if (status == QProcess::NormalExit && exitCode == 0) {
@@ -338,7 +338,7 @@ void AbstractProcessStep::processStartupFailed()
bool AbstractProcessStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
{
- if (outputParser() && outputParser()->hasFatalErrors())
+ if (outputParser()->hasFatalErrors())
return false;
return exitCode == 0 && status == QProcess::NormalExit;
@@ -359,8 +359,7 @@ void AbstractProcessStep::processReadyReadStdOutput()
void AbstractProcessStep::stdOutput(const QString &output)
{
- if (d->m_outputParserChain)
- d->m_outputParserChain->handleStdout(output);
+ d->m_outputParser.handleStdout(output);
emit addOutput(output, BuildStep::OutputFormat::Stdout, BuildStep::DontAppendNewline);
}
@@ -379,8 +378,7 @@ void AbstractProcessStep::processReadyReadStdError()
void AbstractProcessStep::stdError(const QString &output)
{
- if (d->m_outputParserChain)
- d->m_outputParserChain->handleStderr(output);
+ d->m_outputParser.handleStderr(output);
emit addOutput(output, BuildStep::OutputFormat::Stderr, BuildStep::DontAppendNewline);
}
@@ -396,13 +394,6 @@ void AbstractProcessStep::taskAdded(const Task &task, int linkedOutputLines, int
if (d->m_ignoreReturnValue)
return;
- // flush out any pending tasks before proceeding:
- if (!d->m_skipFlush && d->m_outputParserChain) {
- d->m_skipFlush = true;
- d->m_outputParserChain->flushTasks();
- d->m_skipFlush = false;
- }
-
Task editable(task);
QString filePath = task.file.toString();
if (!filePath.isEmpty() && !filePath.startsWith('<') && !QDir::isAbsolutePath(filePath)) {
diff --git a/src/plugins/projectexplorer/abstractprocessstep.h b/src/plugins/projectexplorer/abstractprocessstep.h
index 12c1fdecbf..2ad1c1609f 100644
--- a/src/plugins/projectexplorer/abstractprocessstep.h
+++ b/src/plugins/projectexplorer/abstractprocessstep.h
@@ -48,6 +48,7 @@ public:
void setOutputParser(IOutputParser *parser);
void appendOutputParser(IOutputParser *parser);
+ void appendOutputParsers(const QList<IOutputParser *> &parsers);
IOutputParser *outputParser() const;
void emitFaultyConfigurationMessage();
diff --git a/src/plugins/projectexplorer/clangparser.cpp b/src/plugins/projectexplorer/clangparser.cpp
index 4e0bb63fdd..c2deba71ae 100644
--- a/src/plugins/projectexplorer/clangparser.cpp
+++ b/src/plugins/projectexplorer/clangparser.cpp
@@ -25,6 +25,7 @@
#include "clangparser.h"
#include "ldparser.h"
+#include "lldparser.h"
#include "projectexplorerconstants.h"
using namespace ProjectExplorer;
@@ -54,25 +55,28 @@ ClangParser::ClangParser() :
setObjectName(QLatin1String("ClangParser"));
}
-void ClangParser::handleLine(const QString &line, OutputFormat type)
+QList<IOutputParser *> ClangParser::clangParserSuite()
{
- if (type != StdErrFormat) {
- IOutputParser::handleLine(line, type);
- return;
- }
+ return {new ClangParser, new Internal::LldParser, new LdParser};
+}
+
+IOutputParser::Status ClangParser::doHandleLine(const QString &line, OutputFormat type)
+{
+ if (type != StdErrFormat)
+ return Status::NotHandled;
const QString lne = rightTrimmed(line);
QRegularExpressionMatch match = m_summaryRegExp.match(lne);
if (match.hasMatch()) {
doFlush();
m_expectSnippet = false;
- return;
+ return Status::Done;
}
match = m_commandRegExp.match(lne);
if (match.hasMatch()) {
m_expectSnippet = true;
newTask(CompileTask(taskType(match.captured(3)), match.captured(4)));
- return;
+ return Status::InProgress;
}
match = m_inLineRegExp.match(lne);
@@ -82,7 +86,7 @@ void ClangParser::handleLine(const QString &line, OutputFormat type)
lne.trimmed(),
absoluteFilePath(FilePath::fromUserInput(match.captured(2))),
match.captured(3).toInt() /* line */));
- return;
+ return Status::InProgress;
}
match = m_messageRegExp.match(lne);
@@ -96,22 +100,22 @@ void ClangParser::handleLine(const QString &line, OutputFormat type)
match.captured(8),
absoluteFilePath(FilePath::fromUserInput(match.captured(1))),
lineNo));
- return;
+ return Status::InProgress;
}
match = m_codesignRegExp.match(lne);
if (match.hasMatch()) {
m_expectSnippet = true;
newTask(CompileTask(Task::Error, match.captured(1)));
- return;
+ return Status::InProgress;
}
if (m_expectSnippet) {
amendDescription(lne, true);
- return;
+ return Status::InProgress;
}
- IOutputParser::handleLine(line, StdErrFormat);
+ return Status::NotHandled;
}
Core::Id ClangParser::id()
@@ -259,7 +263,7 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
void ProjectExplorerPlugin::testClangOutputParser()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new ClangParser);
+ testbench.setLineParsers(ClangParser::clangParserSuite());
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/projectexplorer/clangparser.h b/src/plugins/projectexplorer/clangparser.h
index d6ed0e2eaf..b6ef7eb2a0 100644
--- a/src/plugins/projectexplorer/clangparser.h
+++ b/src/plugins/projectexplorer/clangparser.h
@@ -39,10 +39,12 @@ class PROJECTEXPLORER_EXPORT ClangParser : public ProjectExplorer::GccParser
public:
ClangParser();
+ static QList<IOutputParser *> clangParserSuite();
+
static Core::Id id();
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
QRegularExpression m_commandRegExp;
QRegularExpression m_inLineRegExp;
diff --git a/src/plugins/projectexplorer/customparser.cpp b/src/plugins/projectexplorer/customparser.cpp
index 8ee8c900de..514a6bd12a 100644
--- a/src/plugins/projectexplorer/customparser.cpp
+++ b/src/plugins/projectexplorer/customparser.cpp
@@ -129,14 +129,14 @@ Core::Id CustomParser::id()
return Core::Id("ProjectExplorer.OutputParser.Custom");
}
-void CustomParser::handleLine(const QString &line, OutputFormat type)
+IOutputParser::Status CustomParser::doHandleLine(const QString &line, OutputFormat type)
{
const CustomParserExpression::CustomParserChannel channel = type == StdErrFormat
? CustomParserExpression::ParseStdErrChannel
: CustomParserExpression::ParseStdOutChannel;
if (parseLine(line, channel))
- return;
- IOutputParser::handleLine(line, type);
+ return Status::Done;
+ return Status::NotHandled;
}
bool CustomParser::hasMatch(const QString &line, CustomParserExpression::CustomParserChannel channel,
@@ -467,7 +467,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers()
parser->skipFileExistsCheck();
OutputParserTester testbench;
- testbench.appendOutputParser(parser);
+ testbench.addLineParser(parser);
testbench.testParsing(input, inputChannel,
tasks, childStdOutLines, childStdErrLines,
outputLines);
diff --git a/src/plugins/projectexplorer/customparser.h b/src/plugins/projectexplorer/customparser.h
index 0df842b04b..db1f0b4c8e 100644
--- a/src/plugins/projectexplorer/customparser.h
+++ b/src/plugins/projectexplorer/customparser.h
@@ -91,7 +91,7 @@ public:
static Core::Id id();
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
bool hasMatch(const QString &line, CustomParserExpression::CustomParserChannel channel,
const CustomParserExpression &expression, Task::TaskType taskType);
diff --git a/src/plugins/projectexplorer/customtoolchain.cpp b/src/plugins/projectexplorer/customtoolchain.cpp
index e24e859862..7c8de01d34 100644
--- a/src/plugins/projectexplorer/customtoolchain.cpp
+++ b/src/plugins/projectexplorer/customtoolchain.cpp
@@ -196,19 +196,19 @@ QStringList CustomToolChain::suggestedMkspecList() const
return m_mkspecs;
}
-IOutputParser *CustomToolChain::outputParser() const
+QList<IOutputParser *> CustomToolChain::outputParsers() const
{
if (m_outputParserId == GccParser::id())
- return new GccParser;
+ return GccParser::gccParserSuite();
if (m_outputParserId == ClangParser::id())
- return new ClangParser;
+ return ClangParser::clangParserSuite();
if (m_outputParserId == LinuxIccParser::id())
- return new LinuxIccParser;
+ return LinuxIccParser::iccParserSuite();
if (m_outputParserId == MsvcParser::id())
- return new MsvcParser;
+ return {new MsvcParser};
if (m_outputParserId == CustomParser::id())
- return new CustomParser(m_customParserSettings);
- return nullptr;
+ return {new CustomParser(m_customParserSettings)};
+ return {};
}
QStringList CustomToolChain::headerPathsList() const
diff --git a/src/plugins/projectexplorer/customtoolchain.h b/src/plugins/projectexplorer/customtoolchain.h
index 074a09e0f5..d554d44f4f 100644
--- a/src/plugins/projectexplorer/customtoolchain.h
+++ b/src/plugins/projectexplorer/customtoolchain.h
@@ -84,7 +84,7 @@ public:
const Utils::Environment &env) const override;
void addToEnvironment(Utils::Environment &env) const override;
QStringList suggestedMkspecList() const override;
- IOutputParser *outputParser() const override;
+ QList<IOutputParser *> outputParsers() const override;
QStringList headerPathsList() const;
void setHeaderPaths(const QStringList &list);
diff --git a/src/plugins/projectexplorer/gccparser.cpp b/src/plugins/projectexplorer/gccparser.cpp
index a96e0b2cf2..22fc040ed0 100644
--- a/src/plugins/projectexplorer/gccparser.cpp
+++ b/src/plugins/projectexplorer/gccparser.cpp
@@ -59,27 +59,75 @@ GccParser::GccParser()
// optional .exe postfix
m_regExpGccNames.setPattern(QLatin1String(COMMAND_PATTERN));
QTC_CHECK(m_regExpGccNames.isValid());
+}
+
+Core::Id GccParser::id()
+{
+ return Core::Id("ProjectExplorer.OutputParser.Gcc");
+}
+
+QList<IOutputParser *> GccParser::gccParserSuite()
+{
+ return {new GccParser, new Internal::LldParser, new LdParser};
+}
+
+void GccParser::newTask(const Task &task)
+{
+ doFlush();
+ m_currentTask = task;
+ m_lines = 1;
+}
+
+void GccParser::doFlush()
+{
+ if (m_currentTask.isNull())
+ return;
+ Task t = m_currentTask;
+ m_currentTask.clear();
+ emit addTask(t, m_lines, 1);
+ m_lines = 0;
+}
- appendOutputParser(new Internal::LldParser);
- appendOutputParser(new LdParser);
+void GccParser::amendDescription(const QString &desc, bool monospaced)
+{
+ if (m_currentTask.isNull())
+ return;
+ int start = m_currentTask.description.count() + 1;
+ m_currentTask.description.append(QLatin1Char('\n'));
+ m_currentTask.description.append(desc);
+ if (monospaced) {
+ QTextLayout::FormatRange fr;
+ fr.start = start;
+ fr.length = desc.count() + 1;
+ fr.format.setFont(TextEditor::TextEditorSettings::fontSettings().font());
+ fr.format.setFontStyleHint(QFont::Monospace);
+ m_currentTask.formats.append(fr);
+ }
+ ++m_lines;
+ return;
}
-void GccParser::stdError(const QString &line)
+IOutputParser::Status GccParser::doHandleLine(const QString &line, OutputFormat type)
{
- QString lne = rightTrimmed(line);
+ if (type == StdOutFormat) {
+ // TODO: The "flush on channel switch" logic could possibly also done centrally.
+ // But see MSVC with the stdout/stderr switches because of jom
+ doFlush();
+ return Status::NotHandled;
+ }
+
+ const QString lne = rightTrimmed(line);
// Blacklist some lines to not handle them:
if (lne.startsWith(QLatin1String("TeamBuilder ")) ||
lne.startsWith(QLatin1String("distcc["))) {
- IOutputParser::handleLine(line, StdErrFormat);
- return;
+ return Status::NotHandled;
}
// Handle misc issues:
- if (lne.startsWith(QLatin1String("ERROR:")) ||
- lne == QLatin1String("* cpp failed")) {
+ if (lne.startsWith(QLatin1String("ERROR:")) || lne == QLatin1String("* cpp failed")) {
newTask(CompileTask(Task::Error, lne /* description */));
- return;
+ return Status::InProgress;
}
QRegularExpressionMatch match = m_regExpGccNames.match(lne);
@@ -93,7 +141,7 @@ void GccParser::stdError(const QString &line)
description = description.mid(7);
}
newTask(CompileTask(type, description));
- return;
+ return Status::InProgress;
}
match = m_regExp.match(lne);
@@ -114,7 +162,7 @@ void GccParser::stdError(const QString &line)
description = match.captured(5) + description;
newTask(CompileTask(type, description, absoluteFilePath(filename), lineno));
- return;
+ return Status::InProgress;
}
match = m_regExpIncluded.match(lne);
@@ -123,69 +171,14 @@ void GccParser::stdError(const QString &line)
lne.trimmed() /* description */,
absoluteFilePath(Utils::FilePath::fromUserInput(match.captured(1))),
match.captured(3).toInt() /* linenumber */));
- return;
+ return Status::InProgress;
} else if (lne.startsWith(' ') && !m_currentTask.isNull()) {
amendDescription(lne, true);
- return;
+ return Status::InProgress;
}
doFlush();
- IOutputParser::handleLine(line, StdErrFormat);
-}
-
-void GccParser::stdOutput(const QString &line)
-{
- doFlush();
- IOutputParser::handleLine(line, StdOutFormat);
-}
-
-Core::Id GccParser::id()
-{
- return Core::Id("ProjectExplorer.OutputParser.Gcc");
-}
-
-void GccParser::newTask(const Task &task)
-{
- doFlush();
- m_currentTask = task;
- m_lines = 1;
-}
-
-void GccParser::doFlush()
-{
- if (m_currentTask.isNull())
- return;
- Task t = m_currentTask;
- m_currentTask.clear();
- emit addTask(t, m_lines, 1);
- m_lines = 0;
-}
-
-void GccParser::amendDescription(const QString &desc, bool monospaced)
-{
- if (m_currentTask.isNull())
- return;
- int start = m_currentTask.description.count() + 1;
- m_currentTask.description.append(QLatin1Char('\n'));
- m_currentTask.description.append(desc);
- if (monospaced) {
- QTextLayout::FormatRange fr;
- fr.start = start;
- fr.length = desc.count() + 1;
- fr.format.setFont(TextEditor::TextEditorSettings::fontSettings().font());
- fr.format.setFontStyleHint(QFont::Monospace);
- m_currentTask.formats.append(fr);
- }
- ++m_lines;
- return;
-}
-
-void GccParser::handleLine(const QString &line, OutputFormat type)
-{
- if (type == StdOutFormat)
- stdOutput(line);
- else
- stdError(line);
+ return Status::NotHandled;
}
// Unit tests:
@@ -1130,7 +1123,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
void ProjectExplorerPlugin::testGccOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new GccParser);
+ testbench.setLineParsers(GccParser::gccParserSuite());
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/projectexplorer/gccparser.h b/src/plugins/projectexplorer/gccparser.h
index 6d795c6750..e2010a7cf3 100644
--- a/src/plugins/projectexplorer/gccparser.h
+++ b/src/plugins/projectexplorer/gccparser.h
@@ -42,6 +42,8 @@ public:
static Core::Id id();
+ static QList<IOutputParser *> gccParserSuite();
+
protected:
void newTask(const Task &task);
void doFlush() override;
@@ -49,10 +51,7 @@ protected:
void amendDescription(const QString &desc, bool monospaced);
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
-
- void stdError(const QString &line);
- void stdOutput(const QString &line);
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
QRegularExpression m_regExp;
QRegularExpression m_regExpIncluded;
diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp
index 4b2d04e6e0..cb4f8ce216 100644
--- a/src/plugins/projectexplorer/gcctoolchain.cpp
+++ b/src/plugins/projectexplorer/gcctoolchain.cpp
@@ -731,9 +731,9 @@ FilePath GccToolChain::makeCommand(const Environment &environment) const
return tmp.isEmpty() ? FilePath::fromString("make") : tmp;
}
-IOutputParser *GccToolChain::outputParser() const
+QList<IOutputParser *> GccToolChain::outputParsers() const
{
- return new GccParser;
+ return GccParser::gccParserSuite();
}
void GccToolChain::resetToolChain(const FilePath &path)
@@ -1628,9 +1628,9 @@ LanguageExtensions ClangToolChain::defaultLanguageExtensions() const
return LanguageExtension::Gnu;
}
-IOutputParser *ClangToolChain::outputParser() const
+QList<IOutputParser *> ClangToolChain::outputParsers() const
{
- return new ClangParser;
+ return ClangParser::clangParserSuite();
}
// --------------------------------------------------------------------------
@@ -1898,9 +1898,9 @@ LanguageExtensions LinuxIccToolChain::languageExtensions(const QStringList &cxxf
return extensions;
}
-IOutputParser *LinuxIccToolChain::outputParser() const
+QList<IOutputParser *> LinuxIccToolChain::outputParsers() const
{
- return new LinuxIccParser;
+ return LinuxIccParser::iccParserSuite();
}
QStringList LinuxIccToolChain::suggestedMkspecList() const
diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h
index a0761aa1fe..60d68d66a2 100644
--- a/src/plugins/projectexplorer/gcctoolchain.h
+++ b/src/plugins/projectexplorer/gcctoolchain.h
@@ -94,7 +94,7 @@ public:
void addToEnvironment(Utils::Environment &env) const override;
Utils::FilePath makeCommand(const Utils::Environment &environment) const override;
QStringList suggestedMkspecList() const override;
- IOutputParser *outputParser() const override;
+ QList<IOutputParser *> outputParsers() const override;
QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override;
@@ -226,7 +226,7 @@ public:
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override;
Utils::WarningFlags warningFlags(const QStringList &cflags) const override;
- IOutputParser *outputParser() const override;
+ QList<IOutputParser *> outputParsers() const override;
QStringList suggestedMkspecList() const override;
void addToEnvironment(Utils::Environment &env) const override;
@@ -286,7 +286,7 @@ class PROJECTEXPLORER_EXPORT LinuxIccToolChain : public GccToolChain
public:
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override;
- IOutputParser *outputParser() const override;
+ QList<IOutputParser *> outputParsers() const override;
QStringList suggestedMkspecList() const override;
diff --git a/src/plugins/projectexplorer/gnumakeparser.cpp b/src/plugins/projectexplorer/gnumakeparser.cpp
index 2d8769d8db..f9d681348d 100644
--- a/src/plugins/projectexplorer/gnumakeparser.cpp
+++ b/src/plugins/projectexplorer/gnumakeparser.cpp
@@ -56,35 +56,6 @@ GnuMakeParser::GnuMakeParser()
QTC_CHECK(m_errorInMakefile.isValid());
}
-void GnuMakeParser::handleLine(const QString &line, OutputFormat type)
-{
- if (type == StdOutFormat)
- stdOutput(line);
- else
- stdError(line);
-}
-
-bool GnuMakeParser::hasFatalErrors() const
-{
- return (m_fatalErrorCount > 0) || IOutputParser::hasFatalErrors();
-}
-
-void GnuMakeParser::stdOutput(const QString &line)
-{
- const QString lne = rightTrimmed(line);
-
- QRegularExpressionMatch match = m_makeDir.match(lne);
- if (match.hasMatch()) {
- if (match.captured(6) == QLatin1String("Leaving"))
- dropSearchDir(FilePath::fromString(match.captured(7)));
- else
- addSearchDir(FilePath::fromString(match.captured(7)));
- return;
- }
-
- IOutputParser::handleLine(line, StdOutFormat);
-}
-
class Result {
public:
Result() = default;
@@ -125,13 +96,29 @@ static Result parseDescription(const QString &description)
return result;
}
-void GnuMakeParser::stdError(const QString &line)
+void GnuMakeParser::emitTask(const ProjectExplorer::Task &task)
{
- const QString lne = rightTrimmed(line);
+ if (task.type == Task::Error) // Assume that all make errors will be follow up errors.
+ m_suppressIssues = true;
+ emit addTask(task, 1, 0);
+}
+IOutputParser::Status GnuMakeParser::doHandleLine(const QString &line, OutputFormat type)
+{
+ const QString lne = rightTrimmed(line);
+ if (type == StdOutFormat) {
+ QRegularExpressionMatch match = m_makeDir.match(lne);
+ if (match.hasMatch()) {
+ if (match.captured(6) == QLatin1String("Leaving"))
+ emit searchDirOut(FilePath::fromString(match.captured(7)));
+ else
+ emit searchDirIn(FilePath::fromString(match.captured(7)));
+ return Status::Done;
+ }
+ return Status::NotHandled;
+ }
QRegularExpressionMatch match = m_errorInMakefile.match(lne);
if (match.hasMatch()) {
- flush();
Result res = parseDescription(match.captured(5));
if (res.isFatal)
++m_fatalErrorCount;
@@ -140,27 +127,24 @@ void GnuMakeParser::stdError(const QString &line)
absoluteFilePath(FilePath::fromUserInput(match.captured(1))),
match.captured(4).toInt() /* line */));
}
- return;
+ return Status::Done;
}
match = m_makeLine.match(lne);
if (match.hasMatch()) {
- flush();
Result res = parseDescription(match.captured(6));
if (res.isFatal)
++m_fatalErrorCount;
if (!m_suppressIssues)
emitTask(BuildSystemTask(res.type, res.description));
- return;
+ return Status::Done;
}
- IOutputParser::handleLine(line, StdErrFormat);
+ return Status::NotHandled;
}
-void GnuMakeParser::emitTask(const ProjectExplorer::Task &task)
+bool GnuMakeParser::hasFatalErrors() const
{
- if (task.type == Task::Error) // Assume that all make errors will be follow up errors.
- m_suppressIssues = true;
- emit addTask(task, 1, 0);
+ return (m_fatalErrorCount > 0) || IOutputParser::hasFatalErrors();
}
} // ProjectExplorer
@@ -371,7 +355,7 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing()
connect(&testbench, &OutputParserTester::aboutToDeleteParser,
tester, &GnuMakeParserTester::parserIsAboutToBeDeleted);
- testbench.appendOutputParser(childParser);
+ testbench.addLineParser(childParser);
QFETCH(QStringList, extraSearchDirs);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
@@ -381,11 +365,11 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing()
QFETCH(QString, outputLines);
QFETCH(QStringList, additionalSearchDirs);
- FilePaths searchDirs = childParser->searchDirectories();
+ FilePaths searchDirs = testbench.searchDirectories();
// add extra directories:
foreach (const QString &dir, extraSearchDirs)
- childParser->addSearchDir(FilePath::fromString(dir));
+ testbench.addSearchDir(FilePath::fromString(dir));
testbench.testParsing(input, inputChannel,
tasks, childStdOutLines, childStdErrLines,
@@ -418,7 +402,7 @@ void ProjectExplorerPlugin::testGnuMakeParserTaskMangling()
OutputParserTester testbench;
auto *childParser = new GnuMakeParser;
- testbench.appendOutputParser(childParser);
+ testbench.addLineParser(childParser);
childParser->addSearchDir(FilePath::fromString(fi.absolutePath()));
testbench.testParsing(
fi.fileName() + ":360: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.",
diff --git a/src/plugins/projectexplorer/gnumakeparser.h b/src/plugins/projectexplorer/gnumakeparser.h
index 3557158594..c514f865b6 100644
--- a/src/plugins/projectexplorer/gnumakeparser.h
+++ b/src/plugins/projectexplorer/gnumakeparser.h
@@ -40,12 +40,9 @@ public:
explicit GnuMakeParser();
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
bool hasFatalErrors() const override;
- void stdOutput(const QString &line);
- void stdError(const QString &line);
-
void emitTask(const ProjectExplorer::Task &task);
QRegularExpression m_makeDir;
diff --git a/src/plugins/projectexplorer/ioutputparser.cpp b/src/plugins/projectexplorer/ioutputparser.cpp
index bd9590ef52..72cb25b811 100644
--- a/src/plugins/projectexplorer/ioutputparser.cpp
+++ b/src/plugins/projectexplorer/ioutputparser.cpp
@@ -26,10 +26,12 @@
#include "ioutputparser.h"
#include "task.h"
+#include <utils/algorithm.h>
#include <utils/synchronousprocess.h>
#include <QDir>
#include <QFileInfo>
+#include <QPointer>
/*!
\class ProjectExplorer::IOutputParser
@@ -41,21 +43,7 @@
*/
/*!
- \fn void ProjectExplorer::IOutputParser::appendOutputParser(IOutputParser *parser)
-
- Appends a subparser to this parser, of which IOutputParser will take
- ownership.
-*/
-
-/*!
- \fn IOutputParser *ProjectExplorer::IOutputParser::childParser() const
-
- Returns the head of this parser's output parser children. IOutputParser
- keeps ownership.
-*/
-
-/*!
- \fn void ProjectExplorer::IOutputParser::handleLine(const QString &line, Utils::OutputFormat type)
+ \fn ProjectExplorer::IOutputParser::Status ProjectExplorer::IOutputParser::doHandleLine(const QString &line, Utils::OutputFormat type)
Called once for each line of standard output or standard error to parse.
*/
@@ -67,28 +55,12 @@
*/
/*!
- \fn void ProjectExplorer::IOutputParser::addOutput(const QString &string, ProjectExplorer::BuildStep::OutputFormat format)
-
- Should be emitted whenever some additional information should be added to the
- output.
-
- \note This is additional information. There is no need to add each line.
-*/
-
-/*!
\fn void ProjectExplorer::IOutputParser::addTask(const ProjectExplorer::Task &task)
Should be emitted for each task seen in the output.
*/
/*!
- \fn void ProjectExplorer::IOutputParser::taskAdded(const ProjectExplorer::Task &task)
-
- Subparsers have their addTask signal connected to this slot.
- This function can be overwritten to change the task.
-*/
-
-/*!
\fn void ProjectExplorer::IOutputParser::doFlush()
Instructs a parser to flush its state.
@@ -121,14 +93,14 @@ public:
break;
const QString line = pendingData.left(eolPos + 1);
pendingData.remove(0, eolPos + 1);
- parser->handleLine(parser->filteredLine(line), type);
+ parser->handleLine(line, type);
}
}
void flush()
{
if (!pendingData.isEmpty()) {
- parser->handleLine(parser->filteredLine(pendingData), type);
+ parser->handleLine(pendingData, type);
pendingData.clear();
}
}
@@ -146,11 +118,13 @@ public:
stderrState(parser, Utils::StdErrFormat)
{}
- IOutputParser *childParser = nullptr;
+ QList<IOutputParser *> lineParsers;
+ IOutputParser *nextParser = nullptr;
QList<Filter> filters;
Utils::FilePaths searchDirs;
OutputChannelState stdoutState;
OutputChannelState stderrState;
+ QPointer<const IOutputParser> redirectionDetector;
bool skipFileExistsCheck = false;
};
@@ -160,7 +134,7 @@ IOutputParser::IOutputParser() : d(new IOutputParserPrivate(this))
IOutputParser::~IOutputParser()
{
- delete d->childParser;
+ clear();
delete d;
}
@@ -174,73 +148,115 @@ void IOutputParser::handleStderr(const QString &data)
d->stderrState.handleData(data);
}
-void IOutputParser::appendOutputParser(IOutputParser *parser)
+IOutputParser::Status IOutputParser::doHandleLine(const QString &line, Utils::OutputFormat type)
{
- if (!parser)
- return;
- if (d->childParser) {
- d->childParser->appendOutputParser(parser);
- return;
+ Q_UNUSED(line);
+ Q_UNUSED(type);
+ return Status::NotHandled;
+}
+
+void IOutputParser::doFlush() { }
+
+void IOutputParser::handleLine(const QString &line, Utils::OutputFormat type)
+{
+ const QString cleanLine = filteredLine(line);
+ if (d->nextParser) {
+ switch (d->nextParser->doHandleLine(cleanLine, outputTypeForParser(d->nextParser, type))) {
+ case Status::Done:
+ d->nextParser = nullptr;
+ return;
+ case Status::InProgress:
+ return;
+ case Status::NotHandled:
+ d->nextParser = nullptr;
+ break;
+ }
}
+ QTC_CHECK(!d->nextParser);
+ for (IOutputParser * const lineParser : d->lineParsers) {
+ switch (lineParser->doHandleLine(cleanLine, outputTypeForParser(lineParser, type))) {
+ case Status::Done:
+ return;
+ case Status::InProgress:
+ d->nextParser = lineParser;
+ return;
+ case Status::NotHandled:
+ break;
+ }
+ }
+}
- d->childParser = parser;
- connect(parser, &IOutputParser::addTask, this, &IOutputParser::addTask);
+QString IOutputParser::filteredLine(const QString &line) const
+{
+ QString l = line;
+ for (const IOutputParser::Filter &f : qAsConst(d->filters))
+ l = f(l);
+ return l;
}
-IOutputParser *IOutputParser::childParser() const
+void IOutputParser::connectLineParser(IOutputParser *parser)
{
- return d->childParser;
+ connect(parser, &IOutputParser::addTask, this, &IOutputParser::addTask);
+ connect(parser, &IOutputParser::searchDirIn, this, &IOutputParser::addSearchDir);
+ connect(parser, &IOutputParser::searchDirOut, this, &IOutputParser::dropSearchDir);
}
-void IOutputParser::setChildParser(IOutputParser *parser)
+bool IOutputParser::hasFatalErrors() const
{
- if (d->childParser != parser)
- delete d->childParser;
- d->childParser = parser;
- if (parser)
- connect(parser, &IOutputParser::addTask, this, &IOutputParser::addTask);
+ return Utils::anyOf(d->lineParsers, [](const IOutputParser *p) { return p->hasFatalErrors(); });
}
-void IOutputParser::handleLine(const QString &line, Utils::OutputFormat type)
+void IOutputParser::flush()
{
- if (d->childParser)
- d->childParser->handleLine(line, type);
+ d->stdoutState.flush();
+ d->stderrState.flush();
+ doFlush();
+ for (IOutputParser * const p : qAsConst(d->lineParsers))
+ p->doFlush();
}
-void IOutputParser::skipFileExistsCheck()
+void IOutputParser::clear()
{
- d->skipFileExistsCheck = true;
+ d->nextParser = nullptr;
+ d->redirectionDetector.clear();
+ d->filters.clear();
+ d->searchDirs.clear();
+ qDeleteAll(d->lineParsers);
+ d->lineParsers.clear();
+ d->stdoutState.pendingData.clear();
+ d->stderrState.pendingData.clear();
}
-void IOutputParser::doFlush() { }
+void IOutputParser::addLineParser(IOutputParser *parser)
+{
+ connectLineParser(parser);
+ d->lineParsers << parser;
+}
-QString IOutputParser::filteredLine(const QString &line) const
+void IOutputParser::addLineParsers(const QList<IOutputParser *> &parsers)
{
- QString l = line;
- for (const IOutputParser::Filter &f : qAsConst(d->filters))
- l = f(l);
- return l;
+ for (IOutputParser * const p : qAsConst(parsers))
+ addLineParser(p);
}
-bool IOutputParser::hasFatalErrors() const
+void IOutputParser::setLineParsers(const QList<IOutputParser *> &parsers)
{
- return d->childParser && d->childParser->hasFatalErrors();
+ qDeleteAll(d->lineParsers);
+ d->lineParsers.clear();
+ addLineParsers(parsers);
}
-void IOutputParser::flush()
+#ifdef WITH_TESTS
+QList<IOutputParser *> IOutputParser::lineParsers() const
{
- flushTasks();
- d->stdoutState.flush();
- d->stderrState.flush();
- flushTasks();
+ return d->lineParsers;
}
-void IOutputParser::flushTasks()
+void IOutputParser::skipFileExistsCheck()
{
- doFlush();
- if (d->childParser)
- d->childParser->flushTasks();
+ d->skipFileExistsCheck = true;
}
+#endif // WITH_TESTS
QString IOutputParser::rightTrimmed(const QString &in)
{
@@ -260,8 +276,8 @@ void IOutputParser::addFilter(const Filter &filter)
void IOutputParser::addSearchDir(const Utils::FilePath &dir)
{
d->searchDirs << dir;
- if (d->childParser)
- d->childParser->addSearchDir(dir);
+ for (IOutputParser * const p : qAsConst(d->lineParsers))
+ p->addSearchDir(dir);
}
void IOutputParser::dropSearchDir(const Utils::FilePath &dir)
@@ -269,8 +285,8 @@ void IOutputParser::dropSearchDir(const Utils::FilePath &dir)
const int idx = d->searchDirs.lastIndexOf(dir);
QTC_ASSERT(idx != -1, return);
d->searchDirs.removeAt(idx);
- if (d->childParser)
- d->childParser->dropSearchDir(dir);
+ for (IOutputParser * const p : qAsConst(d->lineParsers))
+ p->dropSearchDir(dir);
}
const Utils::FilePaths IOutputParser::searchDirectories() const
@@ -293,4 +309,27 @@ Utils::FilePath IOutputParser::absoluteFilePath(const Utils::FilePath &filePath)
return filePath;
}
+// The redirection mechanism is needed for broken build tools (e.g. xcodebuild) that get invoked
+// indirectly as part of the build process and redirect their child processes' stderr output
+// to stdout. A parser might be able to detect this condition and inform interested
+// other parsers that they need to interpret stdout data as stderr.
+void IOutputParser::setRedirectionDetector(const IOutputParser *detector)
+{
+ d->redirectionDetector = detector;
+}
+
+bool IOutputParser::needsRedirection() const
+{
+ return d->redirectionDetector && (d->redirectionDetector->hasDetectedRedirection()
+ || d->redirectionDetector->needsRedirection());
+}
+
+Utils::OutputFormat IOutputParser::outputTypeForParser(const IOutputParser *parser,
+ Utils::OutputFormat type) const
+{
+ if (type == Utils::StdOutFormat && parser->needsRedirection())
+ return Utils::StdErrFormat;
+ return type;
+}
+
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/ioutputparser.h b/src/plugins/projectexplorer/ioutputparser.h
index e200f7eef0..3018b58796 100644
--- a/src/plugins/projectexplorer/ioutputparser.h
+++ b/src/plugins/projectexplorer/ioutputparser.h
@@ -47,11 +47,6 @@ public:
void handleStdout(const QString &data);
void handleStderr(const QString &data);
- void appendOutputParser(IOutputParser *parser);
-
- IOutputParser *childParser() const;
- void setChildParser(IOutputParser *parser);
-
virtual bool hasFatalErrors() const;
using Filter = std::function<QString(const QString &)>;
@@ -60,25 +55,44 @@ public:
void addSearchDir(const Utils::FilePath &dir);
void dropSearchDir(const Utils::FilePath &dir);
const Utils::FilePaths searchDirectories() const;
- void skipFileExistsCheck(); // For testing only
- void flush(); // flush pending tasks & output
- void flushTasks(); // flush pending tasks only
+ void flush();
+ void clear();
+
+ void addLineParser(IOutputParser *parser);
+ void addLineParsers(const QList<IOutputParser *> &parsers);
+ void setLineParsers(const QList<IOutputParser *> &parsers);
+
+#ifdef WITH_TESTS
+ QList<IOutputParser *> lineParsers() const;
+ void skipFileExistsCheck();
+#endif
+
+ void setRedirectionDetector(const IOutputParser *detector);
static QString rightTrimmed(const QString &in);
signals:
+ void searchDirIn(const Utils::FilePath &dir);
+ void searchDirOut(const Utils::FilePath &dir);
void addTask(const ProjectExplorer::Task &task, int linkedOutputLines = 0, int skipLines = 0);
protected:
- virtual void handleLine(const QString &line, Utils::OutputFormat type);
+ enum class Status { Done, InProgress, NotHandled };
Utils::FilePath absoluteFilePath(const Utils::FilePath &filePath);
private:
+ virtual Status doHandleLine(const QString &line, Utils::OutputFormat type);
virtual void doFlush();
+ virtual bool hasDetectedRedirection() const { return false; }
+ void handleLine(const QString &line, Utils::OutputFormat type);
QString filteredLine(const QString &line) const;
+ void connectLineParser(IOutputParser *parser);
+ bool needsRedirection() const;
+ Utils::OutputFormat outputTypeForParser(const IOutputParser *parser,
+ Utils::OutputFormat type) const;
class OutputChannelState;
class IOutputParserPrivate;
diff --git a/src/plugins/projectexplorer/kit.cpp b/src/plugins/projectexplorer/kit.cpp
index 75f52ec1c8..52b13dc38d 100644
--- a/src/plugins/projectexplorer/kit.cpp
+++ b/src/plugins/projectexplorer/kit.cpp
@@ -559,12 +559,12 @@ void Kit::addToEnvironment(Environment &env) const
aspect->addToEnvironment(this, env);
}
-IOutputParser *Kit::createOutputParser() const
+QList<IOutputParser *> Kit::createOutputParsers() const
{
- auto first = new OsParser;
+ QList<IOutputParser *> parsers{new OsParser};
for (KitAspect *aspect : KitManager::kitAspects())
- first->appendOutputParser(aspect->createOutputParser(this));
- return first;
+ parsers << aspect->createOutputParsers(this);
+ return parsers;
}
QString Kit::toHtml(const Tasks &additional, const QString &extraText) const
diff --git a/src/plugins/projectexplorer/kit.h b/src/plugins/projectexplorer/kit.h
index fe76b750dc..831a450827 100644
--- a/src/plugins/projectexplorer/kit.h
+++ b/src/plugins/projectexplorer/kit.h
@@ -116,7 +116,7 @@ public:
bool isEqual(const Kit *other) const;
void addToEnvironment(Utils::Environment &env) const;
- IOutputParser *createOutputParser() const;
+ QList<IOutputParser *> createOutputParsers() const;
QString toHtml(const Tasks &additional = Tasks(), const QString &extraText = QString()) const;
Kit *clone(bool keepName = false) const;
diff --git a/src/plugins/projectexplorer/kitinformation.cpp b/src/plugins/projectexplorer/kitinformation.cpp
index d21ededfd7..ef0520e169 100644
--- a/src/plugins/projectexplorer/kitinformation.cpp
+++ b/src/plugins/projectexplorer/kitinformation.cpp
@@ -557,14 +557,13 @@ void ToolChainKitAspect::addToMacroExpander(Kit *kit, Utils::MacroExpander *expa
});
}
-
-IOutputParser *ToolChainKitAspect::createOutputParser(const Kit *k) const
+QList<IOutputParser *> ToolChainKitAspect::createOutputParsers(const Kit *k) const
{
for (const Core::Id langId : {Constants::CXX_LANGUAGE_ID, Constants::C_LANGUAGE_ID}) {
if (const ToolChain * const tc = toolChain(k, langId))
- return tc->outputParser();
+ return tc->outputParsers();
}
- return nullptr;
+ return {};
}
QSet<Core::Id> ToolChainKitAspect::availableFeatures(const Kit *k) const
diff --git a/src/plugins/projectexplorer/kitinformation.h b/src/plugins/projectexplorer/kitinformation.h
index e4179f2a61..4eb3417195 100644
--- a/src/plugins/projectexplorer/kitinformation.h
+++ b/src/plugins/projectexplorer/kitinformation.h
@@ -84,7 +84,7 @@ public:
void addToEnvironment(const Kit *k, Utils::Environment &env) const override;
void addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const override;
- IOutputParser *createOutputParser(const Kit *k) const override;
+ QList<IOutputParser *> createOutputParsers(const Kit *k) const override;
QSet<Core::Id> availableFeatures(const Kit *k) const override;
static Core::Id id();
diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp
index f989b955cc..72b727847b 100644
--- a/src/plugins/projectexplorer/kitmanager.cpp
+++ b/src/plugins/projectexplorer/kitmanager.cpp
@@ -677,10 +677,10 @@ void KitAspect::addToEnvironment(const Kit *k, Environment &env) const
Q_UNUSED(env)
}
-IOutputParser *KitAspect::createOutputParser(const Kit *k) const
+QList<IOutputParser *> KitAspect::createOutputParsers(const Kit *k) const
{
Q_UNUSED(k)
- return nullptr;
+ return {};
}
QString KitAspect::displayNamePostfix(const Kit *k) const
diff --git a/src/plugins/projectexplorer/kitmanager.h b/src/plugins/projectexplorer/kitmanager.h
index 21228f44c2..d70c2f42b5 100644
--- a/src/plugins/projectexplorer/kitmanager.h
+++ b/src/plugins/projectexplorer/kitmanager.h
@@ -91,7 +91,7 @@ public:
virtual KitAspectWidget *createConfigWidget(Kit *) const = 0;
virtual void addToEnvironment(const Kit *k, Utils::Environment &env) const;
- virtual IOutputParser *createOutputParser(const Kit *k) const;
+ virtual QList<IOutputParser *> createOutputParsers(const Kit *k) const;
virtual QString displayNamePostfix(const Kit *k) const;
diff --git a/src/plugins/projectexplorer/ldparser.cpp b/src/plugins/projectexplorer/ldparser.cpp
index 4892ae90d5..f99a02d354 100644
--- a/src/plugins/projectexplorer/ldparser.cpp
+++ b/src/plugins/projectexplorer/ldparser.cpp
@@ -54,27 +54,27 @@ LdParser::LdParser()
QTC_CHECK(m_regExpGccNames.isValid());
}
-void LdParser::handleLine(const QString &line, Utils::OutputFormat type)
+IOutputParser::Status LdParser::doHandleLine(const QString &line, Utils::OutputFormat type)
{
- if (type != Utils::StdErrFormat) {
- IOutputParser::handleLine(line, type);
- return;
- }
+ if (type != Utils::StdErrFormat)
+ return Status::NotHandled;
+
QString lne = rightTrimmed(line);
- if (!lne.isEmpty() && !lne.at(0).isSpace() && !m_incompleteTask.isNull())
- flush();
+ if (!lne.isEmpty() && !lne.at(0).isSpace() && !m_incompleteTask.isNull()) {
+ doFlush();
+ return Status::NotHandled;
+ }
if (lne.startsWith(QLatin1String("TeamBuilder "))
|| lne.startsWith(QLatin1String("distcc["))
|| lne.contains(QLatin1String("ar: creating "))) {
- IOutputParser::handleLine(line, Utils::StdErrFormat);
- return;
+ return Status::NotHandled;
}
// ld on macOS
if (lne.startsWith("Undefined symbols for architecture") && lne.endsWith(":")) {
m_incompleteTask = CompileTask(Task::Error, lne);
- return;
+ return Status::InProgress;
}
if (!m_incompleteTask.isNull() && lne.startsWith(" ")) {
m_incompleteTask.description.append('\n').append(lne);
@@ -82,19 +82,19 @@ void LdParser::handleLine(const QString &line, Utils::OutputFormat type)
const QRegularExpressionMatch match = locRegExp.match(lne);
if (match.hasMatch())
m_incompleteTask.setFile(Utils::FilePath::fromString(match.captured("file")));
- return;
+ return Status::InProgress;
}
if (lne.startsWith("collect2:") || lne.startsWith("collect2.exe:")) {
emit addTask(CompileTask(Task::Error, lne /* description */), 1);
- return;
+ return Status::Done;
}
QRegularExpressionMatch match = m_ranlib.match(lne);
if (match.hasMatch()) {
QString description = match.captured(2);
emit addTask(CompileTask(Task::Warning, description), 1);
- return;
+ return Status::Done;
}
match = m_regExpGccNames.match(lne);
@@ -108,7 +108,7 @@ void LdParser::handleLine(const QString &line, Utils::OutputFormat type)
description = description.mid(7);
}
emit addTask(CompileTask(type, description), 1);
- return;
+ return Status::Done;
}
match = m_regExpLinker.match(lne);
@@ -138,10 +138,10 @@ void LdParser::handleLine(const QString &line, Utils::OutputFormat type)
description = description.mid(9);
}
emit addTask(CompileTask(type, description, absoluteFilePath(filename), lineno), 1);
- return;
+ return Status::Done;
}
- IOutputParser::handleLine(line, Utils::StdErrFormat);
+ return Status::NotHandled;
}
void LdParser::doFlush()
diff --git a/src/plugins/projectexplorer/ldparser.h b/src/plugins/projectexplorer/ldparser.h
index a2b48a9c20..e07931636a 100644
--- a/src/plugins/projectexplorer/ldparser.h
+++ b/src/plugins/projectexplorer/ldparser.h
@@ -39,7 +39,7 @@ class LdParser : public ProjectExplorer::IOutputParser
public:
LdParser();
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
void doFlush() override;
QRegularExpression m_ranlib;
diff --git a/src/plugins/projectexplorer/linuxiccparser.cpp b/src/plugins/projectexplorer/linuxiccparser.cpp
index 4d25e7f31e..a8ba996ea5 100644
--- a/src/plugins/projectexplorer/linuxiccparser.cpp
+++ b/src/plugins/projectexplorer/linuxiccparser.cpp
@@ -63,21 +63,15 @@ LinuxIccParser::LinuxIccParser() :
m_pchInfoLine.setPattern(QLatin1String("^\".*\": (creating|using) precompiled header file \".*\"\n$"));
m_pchInfoLine.setMinimal(true);
QTC_CHECK(m_pchInfoLine.isValid());
-
- appendOutputParser(new Internal::LldParser);
- appendOutputParser(new LdParser);
}
-void LinuxIccParser::handleLine(const QString &line, OutputFormat type)
+IOutputParser::Status LinuxIccParser::doHandleLine(const QString &line, OutputFormat type)
{
- if (type != Utils::StdErrFormat) {
- IOutputParser::handleLine(line, type);
- return;
- }
- if (m_pchInfoLine.indexIn(line) != -1) {
- // totally ignore this line
- return;
- }
+ if (type != Utils::StdErrFormat)
+ return Status::NotHandled;
+
+ if (m_pchInfoLine.indexIn(line) != -1)
+ return Status::Done; // totally ignore this line
if (m_expectFirstLine && m_firstLine.indexIn(line) != -1) {
// Clear out old task
@@ -94,7 +88,9 @@ void LinuxIccParser::handleLine(const QString &line, OutputFormat type)
m_lines = 1;
m_expectFirstLine = false;
- } else if (!m_expectFirstLine && m_caretLine.indexIn(line) != -1) {
+ return Status::InProgress;
+ }
+ if (!m_expectFirstLine && m_caretLine.indexIn(line) != -1) {
// Format the last line as code
QTextLayout::FormatRange fr;
fr.start = m_temporary.description.lastIndexOf(QLatin1Char('\n')) + 1;
@@ -107,20 +103,25 @@ void LinuxIccParser::handleLine(const QString &line, OutputFormat type)
fr2.length = 1;
fr2.format.setFontWeight(QFont::Bold);
m_temporary.formats.append(fr2);
- } else if (!m_expectFirstLine && line.trimmed().isEmpty()) { // last Line
+ return Status::InProgress;
+ }
+ if (!m_expectFirstLine && line.trimmed().isEmpty()) { // last Line
m_expectFirstLine = true;
emit addTask(m_temporary, m_lines);
m_temporary = Task();
- } else if (!m_expectFirstLine && m_continuationLines.indexIn(line) != -1) {
+ return Status::Done;
+ }
+ if (!m_expectFirstLine && m_continuationLines.indexIn(line) != -1) {
m_temporary.description.append(QLatin1Char('\n'));
m_indent = 0;
while (m_indent < line.length() && line.at(m_indent).isSpace())
m_indent++;
m_temporary.description.append(m_continuationLines.cap(1).trimmed());
++m_lines;
- } else {
- IOutputParser::handleLine(line, StdErrFormat);
+ return Status::InProgress;
}
+ QTC_CHECK(m_temporary.isNull());
+ return Status::NotHandled;
}
Core::Id LinuxIccParser::id()
@@ -128,6 +129,11 @@ Core::Id LinuxIccParser::id()
return Core::Id("ProjectExplorer.OutputParser.Icc");
}
+QList<IOutputParser *> LinuxIccParser::iccParserSuite()
+{
+ return {new LinuxIccParser, new Internal::LldParser, new LdParser};
+}
+
void LinuxIccParser::doFlush()
{
if (m_temporary.isNull())
@@ -238,7 +244,7 @@ void ProjectExplorerPlugin::testLinuxIccOutputParsers_data()
void ProjectExplorerPlugin::testLinuxIccOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new LinuxIccParser);
+ testbench.setLineParsers(LinuxIccParser::iccParserSuite());
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/projectexplorer/linuxiccparser.h b/src/plugins/projectexplorer/linuxiccparser.h
index 54cd09605d..03dc8ad431 100644
--- a/src/plugins/projectexplorer/linuxiccparser.h
+++ b/src/plugins/projectexplorer/linuxiccparser.h
@@ -41,8 +41,10 @@ public:
static Core::Id id();
+ static QList<IOutputParser *> iccParserSuite();
+
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
void doFlush() override;
QRegExp m_firstLine;
diff --git a/src/plugins/projectexplorer/lldparser.cpp b/src/plugins/projectexplorer/lldparser.cpp
index 233bbfdc05..87097c685a 100644
--- a/src/plugins/projectexplorer/lldparser.cpp
+++ b/src/plugins/projectexplorer/lldparser.cpp
@@ -35,16 +35,15 @@
namespace ProjectExplorer {
namespace Internal {
-void LldParser::handleLine(const QString &line, Utils::OutputFormat type)
+IOutputParser::Status LldParser::doHandleLine(const QString &line, Utils::OutputFormat type)
{
- if (type != Utils::StdErrFormat) {
- IOutputParser::handleLine(line, type);
- return;
- }
+ if (type != Utils::StdErrFormat)
+ return Status::NotHandled;
+
const QString trimmedLine = rightTrimmed(line);
if (trimmedLine.contains("error:") && trimmedLine.contains("lld")) {
emit addTask(CompileTask(Task::Error, trimmedLine));
- return;
+ return Status::Done;
}
static const QStringList prefixes{">>> referenced by ", ">>> defined at ", ">>> "};
for (const QString &prefix : prefixes) {
@@ -70,9 +69,9 @@ void LldParser::handleLine(const QString &line, Utils::OutputFormat type)
trimmedLine.mid(filePathOffset, filePathLen).trimmed());
emit addTask(CompileTask(Task::Unknown, trimmedLine.mid(4).trimmed(),
absoluteFilePath(file), lineNo));
- return;
+ return Status::Done;
}
- IOutputParser::handleLine(line, Utils::StdErrFormat);
+ return Status::NotHandled;
}
} // namespace Internal
diff --git a/src/plugins/projectexplorer/lldparser.h b/src/plugins/projectexplorer/lldparser.h
index a2054e1107..4f254d8a17 100644
--- a/src/plugins/projectexplorer/lldparser.h
+++ b/src/plugins/projectexplorer/lldparser.h
@@ -32,7 +32,7 @@ namespace Internal {
class LldParser : public IOutputParser
{
- void handleLine(const QString &line, Utils::OutputFormat type) override;
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
};
} // namespace Internal
diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp
index 8a067cc1e1..cd873d5ea7 100644
--- a/src/plugins/projectexplorer/makestep.cpp
+++ b/src/plugins/projectexplorer/makestep.cpp
@@ -103,9 +103,7 @@ bool MakeStep::init()
setIgnoreReturnValue(isClean());
setOutputParser(new GnuMakeParser());
- IOutputParser *parser = target()->kit()->createOutputParser();
- if (parser)
- appendOutputParser(parser);
+ appendOutputParsers(target()->kit()->createOutputParsers());
outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
return AbstractProcessStep::init();
diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp
index 6ef6bf792e..d368dcec0f 100644
--- a/src/plugins/projectexplorer/msvcparser.cpp
+++ b/src/plugins/projectexplorer/msvcparser.cpp
@@ -100,79 +100,71 @@ MsvcParser::MsvcParser()
QTC_CHECK(m_additionalInfoRegExp.isValid());
}
-void MsvcParser::stdOutput(const QString &line)
+Core::Id MsvcParser::id()
{
- QRegularExpressionMatch match = m_additionalInfoRegExp.match(line);
- if (line.startsWith(" ") && !match.hasMatch()) {
- if (m_lastTask.isNull())
- return;
+ return Core::Id("ProjectExplorer.OutputParser.Msvc");
+}
- m_lastTask.description.append('\n');
- m_lastTask.description.append(line.mid(8));
- // trim trailing spaces:
- int i = 0;
- for (i = m_lastTask.description.length() - 1; i >= 0; --i) {
- if (!m_lastTask.description.at(i).isSpace())
- break;
- }
- m_lastTask.description.truncate(i + 1);
-
- if (m_lastTask.formats.isEmpty()) {
- QTextLayout::FormatRange fr;
- fr.start = m_lastTask.description.indexOf('\n') + 1;
- fr.length = m_lastTask.description.length() - fr.start;
- fr.format.setFontItalic(true);
- m_lastTask.formats.append(fr);
- } else {
- m_lastTask.formats[0].length = m_lastTask.description.length() - m_lastTask.formats[0].start;
+IOutputParser::Status MsvcParser::doHandleLine(const QString &line, OutputFormat type)
+{
+ if (type == OutputFormat::StdOutFormat) {
+ QRegularExpressionMatch match = m_additionalInfoRegExp.match(line);
+ if (line.startsWith(" ") && !match.hasMatch()) {
+ if (m_lastTask.isNull())
+ return Status::NotHandled;
+
+ m_lastTask.description.append('\n');
+ m_lastTask.description.append(line.mid(8));
+ // trim trailing spaces:
+ int i = 0;
+ for (i = m_lastTask.description.length() - 1; i >= 0; --i) {
+ if (!m_lastTask.description.at(i).isSpace())
+ break;
+ }
+ m_lastTask.description.truncate(i + 1);
+
+ if (m_lastTask.formats.isEmpty()) {
+ QTextLayout::FormatRange fr;
+ fr.start = m_lastTask.description.indexOf('\n') + 1;
+ fr.length = m_lastTask.description.length() - fr.start;
+ fr.format.setFontItalic(true);
+ m_lastTask.formats.append(fr);
+ } else {
+ m_lastTask.formats[0].length = m_lastTask.description.length()
+ - m_lastTask.formats[0].start;
+ }
+ ++m_lines;
+ return Status::InProgress;
}
- ++m_lines;
- return;
- }
- if (processCompileLine(line))
- return;
- if (handleNmakeJomMessage(line, &m_lastTask)) {
- m_lines = 1;
- return;
- }
- if (match.hasMatch()) {
- QString description = match.captured(1)
- + match.captured(4).trimmed();
- if (!match.captured(1).isEmpty())
- description.chop(1); // Remove trailing quote
- m_lastTask = CompileTask(Task::Unknown, description,
- absoluteFilePath(FilePath::fromUserInput(match.captured(2))),
- match.captured(3).toInt() /* linenumber */);
- m_lines = 1;
- return;
+ if (processCompileLine(line))
+ return Status::InProgress;
+ if (handleNmakeJomMessage(line, &m_lastTask)) {
+ m_lines = 1;
+ return Status::InProgress;
+ }
+ if (match.hasMatch()) {
+ QString description = match.captured(1)
+ + match.captured(4).trimmed();
+ if (!match.captured(1).isEmpty())
+ description.chop(1); // Remove trailing quote
+ m_lastTask = CompileTask(Task::Unknown, description,
+ absoluteFilePath(FilePath::fromUserInput(match.captured(2))),
+ match.captured(3).toInt() /* linenumber */);
+ m_lines = 1;
+ return Status::InProgress;
+ }
+ return Status::NotHandled;
}
- IOutputParser::handleLine(line, StdOutFormat);
-}
-void MsvcParser::stdError(const QString &line)
-{
if (processCompileLine(line))
- return;
+ return Status::InProgress;
// Jom outputs errors to stderr
if (handleNmakeJomMessage(line, &m_lastTask)) {
m_lines = 1;
- return;
+ return Status::InProgress;
}
- IOutputParser::handleLine(line, StdErrFormat);
-}
-
-Core::Id MsvcParser::id()
-{
- return Core::Id("ProjectExplorer.OutputParser.Msvc");
-}
-
-void MsvcParser::handleLine(const QString &line, OutputFormat type)
-{
- if (type == OutputFormat::StdOutFormat)
- stdOutput(line);
- else
- stdError(line);
+ return Status::NotHandled;
}
bool MsvcParser::processCompileLine(const QString &line)
@@ -220,24 +212,6 @@ ClangClParser::ClangClParser()
QTC_CHECK(m_compileRegExp.isValid());
}
-void ClangClParser::handleLine(const QString &line, OutputFormat type)
-{
- if (type == StdOutFormat)
- stdOutput(line);
- else
- stdError(line);
-}
-
-void ClangClParser::stdOutput(const QString &line)
-{
- if (handleNmakeJomMessage(line, &m_lastTask)) {
- m_linkedLines = 1;
- doFlush();
- return;
- }
- IOutputParser::handleLine(line, StdOutFormat);
-}
-
// Check for a code marker '~~~~ ^ ~~~~~~~~~~~~' underlining above code.
static inline bool isClangCodeMarker(const QString &trimmedLine)
{
@@ -246,51 +220,59 @@ static inline bool isClangCodeMarker(const QString &trimmedLine)
[] (QChar c) { return c != ' ' && c != '^' && c != '~'; });
}
-void ClangClParser::stdError(const QString &lineIn)
+IOutputParser::Status ClangClParser::doHandleLine(const QString &line, OutputFormat type)
{
- const QString line = IOutputParser::rightTrimmed(lineIn); // Strip \r\n.
+ if (type == StdOutFormat) {
+ if (handleNmakeJomMessage(line, &m_lastTask)) {
+ m_linkedLines = 1;
+ doFlush();
+ return Status::Done;
+ }
+ return Status::NotHandled;
+ }
+ const QString lne = IOutputParser::rightTrimmed(line); // Strip \n.
- if (handleNmakeJomMessage(line, &m_lastTask)) {
+ if (handleNmakeJomMessage(lne, &m_lastTask)) {
m_linkedLines = 1;
doFlush();
- return;
+ return Status::Done;
}
// Finish a sequence of warnings/errors: "2 warnings generated."
- if (!line.isEmpty() && line.at(0).isDigit() && line.endsWith("generated.")) {
+ if (!lne.isEmpty() && lne.at(0).isDigit() && lne.endsWith("generated.")) {
doFlush();
- return;
+ return Status::Done;
}
// Start a new error message by a sequence of "In file included from " which is to be skipped.
- if (line.startsWith("In file included from ")) {
+ if (lne.startsWith("In file included from ")) {
doFlush();
- return;
+ return Status::Done;
}
- QRegularExpressionMatch match = m_compileRegExp.match(line);
+ QRegularExpressionMatch match = m_compileRegExp.match(lne);
if (match.hasMatch()) {
doFlush();
const QPair<FilePath, int> position = parseFileName(match.captured(1));
m_lastTask = CompileTask(taskType(match.captured(2)), match.captured(3).trimmed(),
absoluteFilePath(position.first), position.second);
m_linkedLines = 1;
- return;
+ return Status::InProgress;
}
if (!m_lastTask.isNull()) {
- const QString trimmed = line.trimmed();
+ const QString trimmed = lne.trimmed();
if (isClangCodeMarker(trimmed)) {
doFlush();
- return;
+ return Status::Done;
}
m_lastTask.description.append('\n');
m_lastTask.description.append(trimmed);
++m_linkedLines;
- return;
+ return Status::InProgress;
}
- IOutputParser::handleLine(lineIn, StdErrFormat);
+ return Status::NotHandled;
}
void ClangClParser::doFlush()
@@ -566,7 +548,7 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
void ProjectExplorerPlugin::testMsvcOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new MsvcParser);
+ testbench.addLineParser(new MsvcParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
@@ -645,7 +627,7 @@ void ProjectExplorerPlugin::testClangClOutputParsers_data()
void ProjectExplorerPlugin::testClangClOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new ClangClParser);
+ testbench.addLineParser(new ClangClParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/projectexplorer/msvcparser.h b/src/plugins/projectexplorer/msvcparser.h
index bff487f9fb..fbeb6f1ae6 100644
--- a/src/plugins/projectexplorer/msvcparser.h
+++ b/src/plugins/projectexplorer/msvcparser.h
@@ -43,11 +43,9 @@ public:
static Core::Id id();
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
void doFlush() override;
- void stdOutput(const QString &line);
- void stdError(const QString &line);
bool processCompileLine(const QString &line);
QRegularExpression m_compileRegExp;
@@ -65,12 +63,9 @@ public:
ClangClParser();
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
void doFlush() override;
- void stdOutput(const QString &line);
- void stdError(const QString &line);
-
const QRegularExpression m_compileRegExp;
Task m_lastTask;
int m_linkedLines = 0;
diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp
index 53da86420e..9969d4f035 100644
--- a/src/plugins/projectexplorer/msvctoolchain.cpp
+++ b/src/plugins/projectexplorer/msvctoolchain.cpp
@@ -1169,9 +1169,9 @@ void MsvcToolChain::rescanForCompiler()
});
}
-IOutputParser *MsvcToolChain::outputParser() const
+QList<IOutputParser *> MsvcToolChain::outputParsers() const
{
- return new MsvcParser;
+ return {new MsvcParser};
}
void MsvcToolChain::setupVarsBat(const Abi &abi, const QString &varsBat, const QString &varsBatArg)
@@ -1656,9 +1656,9 @@ QStringList ClangClToolChain::suggestedMkspecList() const
return {mkspec, "win32-clang-msvc"};
}
-IOutputParser *ClangClToolChain::outputParser() const
+QList<IOutputParser *> ClangClToolChain::outputParsers() const
{
- return new ClangClParser;
+ return {new ClangClParser};
}
static inline QString llvmDirKey()
diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h
index 7eba087a19..e6be1608a1 100644
--- a/src/plugins/projectexplorer/msvctoolchain.h
+++ b/src/plugins/projectexplorer/msvctoolchain.h
@@ -89,7 +89,7 @@ public:
Utils::FilePath makeCommand(const Utils::Environment &environment) const override;
Utils::FilePath compilerCommand() const override;
- IOutputParser *outputParser() const override;
+ QList<IOutputParser *> outputParsers() const override;
QString varsBatArg() const { return m_varsBatArg; }
QString varsBat() const { return m_vcvarsBat; }
@@ -174,7 +174,7 @@ public:
QStringList suggestedMkspecList() const override;
void addToEnvironment(Utils::Environment &env) const override;
Utils::FilePath compilerCommand() const override;
- IOutputParser *outputParser() const override;
+ QList<IOutputParser *> outputParsers() const override;
QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override;
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
diff --git a/src/plugins/projectexplorer/osparser.cpp b/src/plugins/projectexplorer/osparser.cpp
index c543aac393..3c1a097446 100644
--- a/src/plugins/projectexplorer/osparser.cpp
+++ b/src/plugins/projectexplorer/osparser.cpp
@@ -36,39 +36,30 @@ OsParser::OsParser()
setObjectName(QLatin1String("OsParser"));
}
-void OsParser::handleLine(const QString &line, Utils::OutputFormat type)
-{
- if (type == Utils::StdOutFormat)
- stdOutput(line);
- else
- stdError(line);
-}
-
-void OsParser::stdError(const QString &line)
+IOutputParser::Status OsParser::doHandleLine(const QString &line, Utils::OutputFormat type)
{
+ if (type == Utils::StdOutFormat) {
+ if (Utils::HostOsInfo::isWindowsHost()) {
+ const QString trimmed = line.trimmed();
+ if (trimmed == QLatin1String("The process cannot access the file because it is "
+ "being used by another process.")) {
+ emit addTask(CompileTask(Task::Error, tr(
+ "The process cannot access the file because it is being used "
+ "by another process.\n"
+ "Please close all running instances of your application before "
+ "starting a build.")));
+ m_hasFatalError = true;
+ return Status::Done;
+ }
+ }
+ return Status::NotHandled;
+ }
if (Utils::HostOsInfo::isLinuxHost()) {
const QString trimmed = line.trimmed();
- if (trimmed.contains(QLatin1String(": error while loading shared libraries:")))
+ if (trimmed.contains(QLatin1String(": error while loading shared libraries:"))) {
emit addTask(CompileTask(Task::Error, trimmed));
- }
- IOutputParser::handleLine(line, Utils::StdErrFormat);
-}
-
-void OsParser::stdOutput(const QString &line)
-{
- if (Utils::HostOsInfo::isWindowsHost()) {
- const QString trimmed = line.trimmed();
- if (trimmed == QLatin1String("The process cannot access the file because it is being used by another process.")) {
- emit addTask(CompileTask(Task::Error, tr(
- "The process cannot access the file because it is being used by another process.\n"
- "Please close all running instances of your application before starting a build.")));
- m_hasFatalError = true;
+ return Status::Done;
}
}
- IOutputParser::handleLine(line, Utils::StdOutFormat);
-}
-
-bool OsParser::hasFatalErrors() const
-{
- return m_hasFatalError || IOutputParser::hasFatalErrors();
+ return Status::NotHandled;
}
diff --git a/src/plugins/projectexplorer/osparser.h b/src/plugins/projectexplorer/osparser.h
index fa56268c65..fd0e9dea20 100644
--- a/src/plugins/projectexplorer/osparser.h
+++ b/src/plugins/projectexplorer/osparser.h
@@ -41,11 +41,8 @@ public:
OsParser();
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
- bool hasFatalErrors() const override;
-
- void stdError(const QString &line);
- void stdOutput(const QString &line);
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
+ bool hasFatalErrors() const override { return m_hasFatalError; }
bool m_hasFatalError = false;
};
diff --git a/src/plugins/projectexplorer/outputparser_test.cpp b/src/plugins/projectexplorer/outputparser_test.cpp
index 8a2bebf09d..5ae0c46aed 100644
--- a/src/plugins/projectexplorer/outputparser_test.cpp
+++ b/src/plugins/projectexplorer/outputparser_test.cpp
@@ -53,12 +53,11 @@ void OutputParserTester::testParsing(const QString &lines,
const QString &childStdErrLines,
const QString &outputLines)
{
- if (!m_terminator) {
- m_terminator = new TestTerminator(this);
- appendOutputParser(m_terminator);
- }
+ const auto terminator = new TestTerminator(this);
+ if (!lineParsers().isEmpty())
+ terminator->setRedirectionDetector(lineParsers().last());
+ addLineParser(terminator);
reset();
- Q_ASSERT(childParser());
if (inputChannel == STDOUT)
handleStdout(lines + '\n');
@@ -68,7 +67,7 @@ void OutputParserTester::testParsing(const QString &lines,
// delete the parser(s) to test
emit aboutToDeleteParser();
- setChildParser(nullptr);
+ setLineParsers({});
QCOMPARE(m_receivedOutput, outputLines);
QCOMPARE(m_receivedStdErrChildLine, childStdErrLines);
@@ -103,13 +102,14 @@ TestTerminator::TestTerminator(OutputParserTester *t) :
m_tester(t)
{ }
-void TestTerminator::handleLine(const QString &line, Utils::OutputFormat type)
+IOutputParser::Status TestTerminator::doHandleLine(const QString &line, Utils::OutputFormat type)
{
- QVERIFY(line.endsWith('\n'));
+ QTC_CHECK(line.endsWith('\n'));
if (type == Utils::StdOutFormat)
m_tester->m_receivedStdOutChildLine.append(line);
else
m_tester->m_receivedStdErrChildLine.append(line);
+ return Status::Done;
}
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/outputparser_test.h b/src/plugins/projectexplorer/outputparser_test.h
index 3d749f422a..1a1fff1e65 100644
--- a/src/plugins/projectexplorer/outputparser_test.h
+++ b/src/plugins/projectexplorer/outputparser_test.h
@@ -69,7 +69,6 @@ private:
QString m_receivedStdOutChildLine;
Tasks m_receivedTasks;
QString m_receivedOutput;
- TestTerminator *m_terminator = nullptr;
friend class TestTerminator;
};
@@ -82,7 +81,7 @@ public:
TestTerminator(OutputParserTester *t);
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
OutputParserTester *m_tester = nullptr;
};
diff --git a/src/plugins/projectexplorer/parseissuesdialog.cpp b/src/plugins/projectexplorer/parseissuesdialog.cpp
index e61b4adc1c..7696950ddb 100644
--- a/src/plugins/projectexplorer/parseissuesdialog.cpp
+++ b/src/plugins/projectexplorer/parseissuesdialog.cpp
@@ -151,12 +151,14 @@ static void parse(QFutureInterface<void> &future, const QString &output,
void ParseIssuesDialog::accept()
{
- std::unique_ptr<IOutputParser> parser(d->kitChooser.currentKit()->createOutputParser());
- if (!parser) {
+ const QList<IOutputParser *> lineParsers = d->kitChooser.currentKit()->createOutputParsers();
+ if (lineParsers.isEmpty()) {
QMessageBox::critical(this, tr("Cannot Parse"), tr("Cannot parse: The chosen kit does "
"not provide an output parser."));
return;
}
+ std::unique_ptr<IOutputParser> parser(new IOutputParser);
+ parser->setLineParsers(lineParsers);
if (d->clearTasksCheckBox.isChecked())
TaskHub::clearTasks();
connect(parser.get(), &IOutputParser::addTask, [](const Task &t) { TaskHub::addTask(t); });
diff --git a/src/plugins/projectexplorer/processstep.cpp b/src/plugins/projectexplorer/processstep.cpp
index 02501150b5..ea8de1cb3b 100644
--- a/src/plugins/projectexplorer/processstep.cpp
+++ b/src/plugins/projectexplorer/processstep.cpp
@@ -100,7 +100,7 @@ ProcessStep::ProcessStep(BuildStepList *bsl, Core::Id id)
bool ProcessStep::init()
{
setupProcessParameters(processParameters());
- setOutputParser(target()->kit()->createOutputParser());
+ appendOutputParsers(target()->kit()->createOutputParsers());
return AbstractProcessStep::init();
}
diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h
index d1a90a2104..9e8b6c087c 100644
--- a/src/plugins/projectexplorer/toolchain.h
+++ b/src/plugins/projectexplorer/toolchain.h
@@ -150,7 +150,7 @@ public:
Core::Id language() const;
virtual Utils::FilePath compilerCommand() const = 0;
- virtual IOutputParser *outputParser() const = 0;
+ virtual QList<IOutputParser *> outputParsers() const = 0;
virtual bool operator ==(const ToolChain &) const;
diff --git a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
index 78fafb5ea7..6e15b14191 100644
--- a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
+++ b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
@@ -324,7 +324,7 @@ public:
void addToEnvironment(Environment &env) const override { Q_UNUSED(env) }
FilePath makeCommand(const Environment &) const override { return FilePath::fromString("make"); }
FilePath compilerCommand() const override { return Utils::FilePath::fromString("/tmp/test/gcc"); }
- IOutputParser *outputParser() const override { return nullptr; }
+ QList<IOutputParser *> outputParsers() const override { return {}; }
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override { return nullptr; }
bool operator ==(const ToolChain &other) const override {
if (!ToolChain::operator==(other))
diff --git a/src/plugins/projectexplorer/xcodebuildparser.cpp b/src/plugins/projectexplorer/xcodebuildparser.cpp
index ea5d2c9b04..12dcac6f5a 100644
--- a/src/plugins/projectexplorer/xcodebuildparser.cpp
+++ b/src/plugins/projectexplorer/xcodebuildparser.cpp
@@ -52,61 +52,47 @@ XcodebuildParser::XcodebuildParser()
QTC_CHECK(m_buildRe.isValid());
}
-void XcodebuildParser::handleLine(const QString &line, OutputFormat type)
-{
- if (type == StdOutFormat)
- stdOutput(line);
- else
- stdError(line);
-}
-
-bool XcodebuildParser::hasFatalErrors() const
-{
- return (m_fatalErrorCount > 0) || IOutputParser::hasFatalErrors();
-}
-
-void XcodebuildParser::stdOutput(const QString &line)
+IOutputParser::Status XcodebuildParser::doHandleLine(const QString &line, OutputFormat type)
{
const QString lne = rightTrimmed(line);
- if (m_buildRe.indexIn(lne) > -1) {
- m_xcodeBuildParserState = InXcodebuild;
- m_lastTarget = m_buildRe.cap(2);
- m_lastProject = m_buildRe.cap(3);
- return;
- }
- if (m_xcodeBuildParserState == InXcodebuild || m_xcodeBuildParserState == UnknownXcodebuildState) {
- if (m_successRe.indexIn(lne) > -1) {
- m_xcodeBuildParserState = OutsideXcodebuild;
- return;
+ if (type == StdOutFormat) {
+ if (m_buildRe.indexIn(lne) > -1) {
+ m_xcodeBuildParserState = InXcodebuild;
+ m_lastTarget = m_buildRe.cap(2);
+ m_lastProject = m_buildRe.cap(3);
+ return Status::Done;
}
- if (lne.endsWith(QLatin1String(signatureChangeEndsWithPattern))) {
- CompileTask task(Task::Warning,
- tr("Replacing signature"),
- absoluteFilePath(FilePath::fromString(
- lne.left(lne.size() - QLatin1String(signatureChangeEndsWithPattern).size()))));
- emit addTask(task, 1);
- return;
+ if (m_xcodeBuildParserState == InXcodebuild
+ || m_xcodeBuildParserState == UnknownXcodebuildState) {
+ if (m_successRe.indexIn(lne) > -1) {
+ m_xcodeBuildParserState = OutsideXcodebuild;
+ return Status::Done;
+ }
+ if (lne.endsWith(QLatin1String(signatureChangeEndsWithPattern))) {
+ CompileTask task(Task::Warning,
+ tr("Replacing signature"),
+ absoluteFilePath(FilePath::fromString(
+ lne.left(lne.size() - QLatin1String(signatureChangeEndsWithPattern).size()))));
+ emit addTask(task, 1);
+ return Status::Done;
+ }
}
- IOutputParser::handleLine(line, StdErrFormat); // ??
- } else {
- IOutputParser::handleLine(line, StdOutFormat);
+ return Status::NotHandled;
}
-}
-
-void XcodebuildParser::stdError(const QString &line)
-{
- const QString lne = rightTrimmed(line);
if (m_failureRe.indexIn(lne) > -1) {
++m_fatalErrorCount;
m_xcodeBuildParserState = UnknownXcodebuildState;
// unfortunately the m_lastTarget, m_lastProject might not be in sync
emit addTask(CompileTask(Task::Error, tr("Xcodebuild failed.")));
- return;
- }
- if (m_xcodeBuildParserState == OutsideXcodebuild) { // also forward if UnknownXcodebuildState ?
- IOutputParser::handleLine(line, StdErrFormat);
- return;
}
+ if (m_xcodeBuildParserState == OutsideXcodebuild)
+ return Status::NotHandled;
+ return Status::Done;
+}
+
+bool XcodebuildParser::hasDetectedRedirection() const
+{
+ return m_xcodeBuildParserState != OutsideXcodebuild;
}
} // namespace ProjectExplorer
@@ -268,7 +254,7 @@ void ProjectExplorerPlugin::testXcodebuildParserParsing()
connect(&testbench, &OutputParserTester::aboutToDeleteParser,
tester, &XcodebuildParserTester::onAboutToDeleteParser);
- testbench.appendOutputParser(childParser);
+ testbench.addLineParser(childParser);
QFETCH(ProjectExplorer::XcodebuildParser::XcodebuildStatus, initialStatus);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
diff --git a/src/plugins/projectexplorer/xcodebuildparser.h b/src/plugins/projectexplorer/xcodebuildparser.h
index 59ee84152b..c2fce0e4a7 100644
--- a/src/plugins/projectexplorer/xcodebuildparser.h
+++ b/src/plugins/projectexplorer/xcodebuildparser.h
@@ -47,11 +47,9 @@ public:
XcodebuildParser();
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
- bool hasFatalErrors() const override;
-
- void stdOutput(const QString &line);
- void stdError(const QString &line);
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
+ bool hasDetectedRedirection() const override;
+ bool hasFatalErrors() const override { return m_fatalErrorCount > 0; }
int m_fatalErrorCount = 0;
QRegExp m_failureRe;
diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
index 43034fd87d..a8ee28540c 100644
--- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
+++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
@@ -169,9 +169,9 @@ bool QbsBuildStep::init()
return false;
delete m_parser;
- m_parser = target()->kit()->createOutputParser();
- if (m_parser)
- connect(m_parser, &ProjectExplorer::IOutputParser::addTask, this, &QbsBuildStep::addTask);
+ m_parser = new IOutputParser;
+ m_parser->setLineParsers(target()->kit()->createOutputParsers());
+ connect(m_parser, &ProjectExplorer::IOutputParser::addTask, this, &QbsBuildStep::addTask);
m_changedFiles = bc->changedFiles();
m_activeFileTags = bc->activeFileTags();
diff --git a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp
index f3c85b388c..d5540b7060 100644
--- a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp
@@ -166,14 +166,22 @@ bool QmakeMakeStep::init()
setOutputParser(new ProjectExplorer::GnuMakeParser());
ToolChain *tc = ToolChainKitAspect::cxxToolChain(target()->kit());
- if (tc && tc->targetAbi().os() == Abi::DarwinOS)
- appendOutputParser(new XcodebuildParser);
- IOutputParser *parser = target()->kit()->createOutputParser();
- if (parser)
- appendOutputParser(parser);
+ IOutputParser *xcodeBuildParser = nullptr;
+ if (tc && tc->targetAbi().os() == Abi::DarwinOS) {
+ xcodeBuildParser = new XcodebuildParser;
+ appendOutputParser(xcodeBuildParser);
+ }
+ QList<IOutputParser *> additionalParsers = target()->kit()->createOutputParsers();
+
+ // make may cause qmake to be run, add last to make sure // it has a low priority.
+ additionalParsers << new QMakeParser;
+
+ if (xcodeBuildParser) {
+ for (IOutputParser * const p : qAsConst(additionalParsers))
+ p->setRedirectionDetector(xcodeBuildParser);
+ }
+ appendOutputParsers(additionalParsers);
outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
- appendOutputParser(new QMakeParser); // make may cause qmake to be run, add last to make sure
- // it has a low priority.
auto rootNode = dynamic_cast<QmakeProFileNode *>(project()->rootProjectNode());
QTC_ASSERT(rootNode, return false);
diff --git a/src/plugins/qmakeprojectmanager/qmakeparser.cpp b/src/plugins/qmakeprojectmanager/qmakeparser.cpp
index 3952e591ec..86a0ffc67b 100644
--- a/src/plugins/qmakeprojectmanager/qmakeparser.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeparser.cpp
@@ -40,12 +40,10 @@ QMakeParser::QMakeParser() : m_error(QLatin1String("^(.+):(\\d+):\\s(.+)$"))
m_error.setMinimal(true);
}
-void QMakeParser::handleLine(const QString &line, OutputFormat type)
+IOutputParser::Status QMakeParser::doHandleLine(const QString &line, OutputFormat type)
{
- if (type != Utils::StdErrFormat) {
- IOutputParser::handleLine(line, type);
- return;
- }
+ if (type != Utils::StdErrFormat)
+ return Status::NotHandled;
QString lne = rightTrimmed(line);
if (m_error.indexIn(lne) > -1) {
QString fileName = m_error.cap(1);
@@ -68,21 +66,21 @@ void QMakeParser::handleLine(const QString &line, OutputFormat type)
absoluteFilePath(FilePath::fromUserInput(fileName)),
m_error.cap(2).toInt() /* line */),
1);
- return;
+ return Status::Done;
}
if (lne.startsWith(QLatin1String("Project ERROR: "))
|| lne.startsWith(QLatin1String("ERROR: "))) {
const QString description = lne.mid(lne.indexOf(QLatin1Char(':')) + 2);
emit addTask(BuildSystemTask(Task::Error, description), 1);
- return;
+ return Status::Done;
}
if (lne.startsWith(QLatin1String("Project WARNING: "))
|| lne.startsWith(QLatin1String("WARNING: "))) {
const QString description = lne.mid(lne.indexOf(QLatin1Char(':')) + 2);
emit addTask(BuildSystemTask(Task::Warning, description), 1);
- return;
+ return Status::Done;
}
- IOutputParser::handleLine(line, StdErrFormat);
+ return Status::NotHandled;
}
} // QmakeProjectManager
@@ -183,7 +181,7 @@ void QmakeProjectManagerPlugin::testQmakeOutputParsers_data()
void QmakeProjectManagerPlugin::testQmakeOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new QMakeParser);
+ testbench.addLineParser(new QMakeParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/qmakeprojectmanager/qmakeparser.h b/src/plugins/qmakeprojectmanager/qmakeparser.h
index 11e0529651..822700efd0 100644
--- a/src/plugins/qmakeprojectmanager/qmakeparser.h
+++ b/src/plugins/qmakeprojectmanager/qmakeparser.h
@@ -41,7 +41,7 @@ public:
QMakeParser();
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
QRegExp m_error;
};
diff --git a/src/plugins/qtsupport/qtkitinformation.cpp b/src/plugins/qtsupport/qtkitinformation.cpp
index 0ff13d07ec..5243699afd 100644
--- a/src/plugins/qtsupport/qtkitinformation.cpp
+++ b/src/plugins/qtsupport/qtkitinformation.cpp
@@ -288,14 +288,11 @@ void QtKitAspect::addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environ
version->addToEnvironment(k, env);
}
-ProjectExplorer::IOutputParser *QtKitAspect::createOutputParser(const ProjectExplorer::Kit *k) const
+QList<IOutputParser *> QtKitAspect::createOutputParsers(const Kit *k) const
{
- if (qtVersion(k)) {
- const auto parser = new Internal::QtTestParser;
- parser->appendOutputParser(new QtParser);
- return parser;
- }
- return nullptr;
+ if (qtVersion(k))
+ return {new Internal::QtTestParser, new QtParser};
+ return {};
}
class QtMacroSubProvider
diff --git a/src/plugins/qtsupport/qtkitinformation.h b/src/plugins/qtsupport/qtkitinformation.h
index d155b8ea5f..e63c75c61e 100644
--- a/src/plugins/qtsupport/qtkitinformation.h
+++ b/src/plugins/qtsupport/qtkitinformation.h
@@ -54,7 +54,7 @@ public:
ItemList toUserOutput(const ProjectExplorer::Kit *k) const override;
void addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const override;
- ProjectExplorer::IOutputParser *createOutputParser(const ProjectExplorer::Kit *k) const override;
+ QList<ProjectExplorer::IOutputParser *> createOutputParsers(const ProjectExplorer::Kit *k) const override;
void addToMacroExpander(ProjectExplorer::Kit *kit, Utils::MacroExpander *expander) const override;
static Core::Id id();
diff --git a/src/plugins/qtsupport/qtparser.cpp b/src/plugins/qtsupport/qtparser.cpp
index edeff3d178..c3fb0d5710 100644
--- a/src/plugins/qtsupport/qtparser.cpp
+++ b/src/plugins/qtsupport/qtparser.cpp
@@ -43,12 +43,11 @@ QtParser::QtParser() :
m_translationRegExp.setMinimal(true);
}
-void QtParser::handleLine(const QString &line, Utils::OutputFormat type)
+IOutputParser::Status QtParser::doHandleLine(const QString &line, Utils::OutputFormat type)
{
- if (type != Utils::StdErrFormat) {
- IOutputParser::handleLine(line, type);
- return;
- }
+ if (type != Utils::StdErrFormat)
+ return Status::NotHandled;
+
QString lne = rightTrimmed(line);
if (m_mocRegExp.indexIn(lne) > -1) {
bool ok;
@@ -65,7 +64,7 @@ void QtParser::handleLine(const QString &line, Utils::OutputFormat type)
absoluteFilePath(Utils::FilePath::fromUserInput(m_mocRegExp.cap(1))),
lineno);
emit addTask(task, 1);
- return;
+ return Status::Done;
}
if (m_translationRegExp.indexIn(lne) > -1) {
Task::TaskType type = Task::Warning;
@@ -74,9 +73,9 @@ void QtParser::handleLine(const QString &line, Utils::OutputFormat type)
CompileTask task(type, m_translationRegExp.cap(2),
absoluteFilePath(Utils::FilePath::fromUserInput(m_translationRegExp.cap(3))));
emit addTask(task, 1);
- return;
+ return Status::Done;
}
- IOutputParser::handleLine(line, Utils::StdErrFormat);
+ return Status::NotHandled;
}
// Unit tests:
@@ -179,7 +178,7 @@ void QtSupportPlugin::testQtOutputParser_data()
void QtSupportPlugin::testQtOutputParser()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new QtParser);
+ testbench.addLineParser(new QtParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/qtsupport/qtparser.h b/src/plugins/qtsupport/qtparser.h
index 62e6fe6622..8fda649bbc 100644
--- a/src/plugins/qtsupport/qtparser.h
+++ b/src/plugins/qtsupport/qtparser.h
@@ -42,7 +42,7 @@ public:
QtParser();
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
QRegExp m_mocRegExp;
QRegExp m_translationRegExp;
diff --git a/src/plugins/qtsupport/qttestparser.cpp b/src/plugins/qtsupport/qttestparser.cpp
index 9c84ee46c0..be3c2920e0 100644
--- a/src/plugins/qtsupport/qttestparser.cpp
+++ b/src/plugins/qtsupport/qttestparser.cpp
@@ -47,12 +47,11 @@ using namespace Utils;
namespace QtSupport {
namespace Internal {
-void QtTestParser::handleLine(const QString &line, OutputFormat type)
+IOutputParser::Status QtTestParser::doHandleLine(const QString &line, OutputFormat type)
{
- if (type != StdOutFormat) {
- IOutputParser::handleLine(line, type);
- return;
- }
+ if (type != StdOutFormat)
+ return Status::NotHandled;
+
const QString theLine = rightTrimmed(line);
static const QRegularExpression triggerPattern("^(?:XPASS|FAIL!) : .+$");
QTC_CHECK(triggerPattern.isValid());
@@ -60,12 +59,10 @@ void QtTestParser::handleLine(const QString &line, OutputFormat type)
emitCurrentTask();
m_currentTask = Task(Task::Error, theLine, FilePath(), -1,
Constants::TASK_CATEGORY_AUTOTEST);
- return;
- }
- if (m_currentTask.isNull()) {
- IOutputParser::handleLine(line, StdOutFormat);
- return;
+ return Status::InProgress;
}
+ if (m_currentTask.isNull())
+ return Status::NotHandled;
static const QRegularExpression locationPattern(HostOsInfo::isWindowsHost()
? QString(QT_TEST_FAIL_WIN_REGEXP)
: QString(QT_TEST_FAIL_UNIX_REGEXP));
@@ -76,9 +73,10 @@ void QtTestParser::handleLine(const QString &line, OutputFormat type)
QDir::fromNativeSeparators(match.captured("file"))));
m_currentTask.line = match.captured("line").toInt();
emitCurrentTask();
- return;
+ return Status::Done;
}
m_currentTask.description.append('\n').append(theLine);
+ return Status::InProgress;
}
void QtTestParser::emitCurrentTask()
@@ -93,7 +91,7 @@ void QtTestParser::emitCurrentTask()
void QtSupportPlugin::testQtTestOutputParser()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new QtTestParser);
+ testbench.addLineParser(new QtTestParser);
const QString input = "random output\n"
"PASS : MyTest::someTest()\n"
"XPASS : MyTest::someTest()\n"
diff --git a/src/plugins/qtsupport/qttestparser.h b/src/plugins/qtsupport/qttestparser.h
index f99faccd25..d32d7a40f4 100644
--- a/src/plugins/qtsupport/qttestparser.h
+++ b/src/plugins/qtsupport/qttestparser.h
@@ -35,7 +35,7 @@ class QtTestParser : public ProjectExplorer::IOutputParser
{
Q_OBJECT
private:
- void handleLine(const QString &line, Utils::OutputFormat type) override;
+ Status doHandleLine(const QString &line, Utils::OutputFormat type) override;
void doFlush() override { emitCurrentTask(); }
void emitCurrentTask();