aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2020-04-16 13:53:05 +0200
committerChristian Kandeler <christian.kandeler@qt.io>2020-04-23 08:47:08 +0000
commit1c6e4fbd3211bc180b0de95d232226825bcb124d (patch)
treec9adce875a62a7fa980eb8a99231034585ae8fbf /src/plugins
parentb7851eeb55fd284bd647b7042e7f94a1ea1d3490 (diff)
Merge output formatters and output parsers
Now only one piece of code needs to be written to both linkify output in an output pane and create tasks for it in the issues pane. The calling sites are also simplified. For instance, until now, build steps had to feed their output parsers manually and then push the created tasks up the signal stack in parallel with the actual output, which the build manager relied upon for cross-linking the output pane content. Afterwards, the output would get forwarded to the formatter (and parsed for ANSI escape codes a second time). In contrast, a build step now just forwards the process output, and task parsing as well as output formatting is done centrally further up the stack. Concrete user-visible improvements so far: - File paths in compiler/linker messages are clickable links now. - QtTest applications now create clickable links also when run as part of a build step, not just in the app output pane. Task-number: QTCREATORBUG-22665 Change-Id: Ic9fb95b2d97f2520ab3ec653315e9219466ec08d Reviewed-by: Christian Kandeler <christian.kandeler@qt.io> Reviewed-by: hjk <hjk@qt.io> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/android/androidbuildapkstep.cpp35
-rw-r--r--src/plugins/android/androidbuildapkstep.h1
-rw-r--r--src/plugins/android/androidpackageinstallationstep.cpp13
-rw-r--r--src/plugins/android/javaparser.cpp9
-rw-r--r--src/plugins/android/javaparser.h2
-rw-r--r--src/plugins/baremetal/iarewparser.cpp18
-rw-r--r--src/plugins/baremetal/iarewparser.h4
-rw-r--r--src/plugins/baremetal/iarewtoolchain.cpp2
-rw-r--r--src/plugins/baremetal/iarewtoolchain.h2
-rw-r--r--src/plugins/baremetal/keilparser.cpp46
-rw-r--r--src/plugins/baremetal/keilparser.h8
-rw-r--r--src/plugins/baremetal/keiltoolchain.cpp2
-rw-r--r--src/plugins/baremetal/keiltoolchain.h2
-rw-r--r--src/plugins/baremetal/sdccparser.cpp14
-rw-r--r--src/plugins/baremetal/sdccparser.h2
-rw-r--r--src/plugins/baremetal/sdcctoolchain.cpp2
-rw-r--r--src/plugins/baremetal/sdcctoolchain.h2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildstep.cpp17
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildstep.h1
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeparser.cpp26
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeparser.h2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprocess.cpp13
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprocess.h5
-rw-r--r--src/plugins/cmakeprojectmanager/servermodereader.cpp10
-rw-r--r--src/plugins/cmakeprojectmanager/servermodereader.h3
-rw-r--r--src/plugins/coreplugin/outputwindow.cpp23
-rw-r--r--src/plugins/ios/iosbuildstep.cpp13
-rw-r--r--src/plugins/ios/iosdsymbuildstep.cpp10
-rw-r--r--src/plugins/ios/iosdsymbuildstep.h1
-rw-r--r--src/plugins/nim/project/nimblebuildstep.cpp23
-rw-r--r--src/plugins/nim/project/nimblebuildstep.h2
-rw-r--r--src/plugins/nim/project/nimcompilerbuildstep.cpp21
-rw-r--r--src/plugins/nim/project/nimcompilerbuildstep.h2
-rw-r--r--src/plugins/nim/project/nimtoolchain.cpp2
-rw-r--r--src/plugins/nim/project/nimtoolchain.h2
-rw-r--r--src/plugins/projectexplorer/CMakeLists.txt1
-rw-r--r--src/plugins/projectexplorer/abstractprocessstep.cpp65
-rw-r--r--src/plugins/projectexplorer/abstractprocessstep.h8
-rw-r--r--src/plugins/projectexplorer/ansifilterparser.cpp164
-rw-r--r--src/plugins/projectexplorer/ansifilterparser.h38
-rw-r--r--src/plugins/projectexplorer/buildmanager.cpp4
-rw-r--r--src/plugins/projectexplorer/buildstep.cpp10
-rw-r--r--src/plugins/projectexplorer/buildstep.h7
-rw-r--r--src/plugins/projectexplorer/clangparser.cpp26
-rw-r--r--src/plugins/projectexplorer/clangparser.h4
-rw-r--r--src/plugins/projectexplorer/compileoutputwindow.cpp103
-rw-r--r--src/plugins/projectexplorer/compileoutputwindow.h9
-rw-r--r--src/plugins/projectexplorer/customparser.cpp40
-rw-r--r--src/plugins/projectexplorer/customparser.h8
-rw-r--r--src/plugins/projectexplorer/customtoolchain.cpp2
-rw-r--r--src/plugins/projectexplorer/customtoolchain.h2
-rw-r--r--src/plugins/projectexplorer/gccparser.cpp33
-rw-r--r--src/plugins/projectexplorer/gccparser.h4
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.cpp6
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.h6
-rw-r--r--src/plugins/projectexplorer/gnumakeparser.cpp18
-rw-r--r--src/plugins/projectexplorer/gnumakeparser.h2
-rw-r--r--src/plugins/projectexplorer/ioutputparser.cpp302
-rw-r--r--src/plugins/projectexplorer/ioutputparser.h93
-rw-r--r--src/plugins/projectexplorer/kit.cpp4
-rw-r--r--src/plugins/projectexplorer/kit.h4
-rw-r--r--src/plugins/projectexplorer/kitinformation.cpp2
-rw-r--r--src/plugins/projectexplorer/kitinformation.h2
-rw-r--r--src/plugins/projectexplorer/kitmanager.cpp2
-rw-r--r--src/plugins/projectexplorer/kitmanager.h4
-rw-r--r--src/plugins/projectexplorer/ldparser.cpp33
-rw-r--r--src/plugins/projectexplorer/ldparser.h2
-rw-r--r--src/plugins/projectexplorer/linuxiccparser.cpp19
-rw-r--r--src/plugins/projectexplorer/linuxiccparser.h4
-rw-r--r--src/plugins/projectexplorer/lldparser.cpp16
-rw-r--r--src/plugins/projectexplorer/lldparser.h2
-rw-r--r--src/plugins/projectexplorer/makestep.cpp12
-rw-r--r--src/plugins/projectexplorer/makestep.h1
-rw-r--r--src/plugins/projectexplorer/msvcparser.cpp43
-rw-r--r--src/plugins/projectexplorer/msvcparser.h6
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.cpp4
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.h4
-rw-r--r--src/plugins/projectexplorer/osparser.cpp8
-rw-r--r--src/plugins/projectexplorer/osparser.h2
-rw-r--r--src/plugins/projectexplorer/outputparser_test.cpp73
-rw-r--r--src/plugins/projectexplorer/outputparser_test.h5
-rw-r--r--src/plugins/projectexplorer/parseissuesdialog.cpp12
-rw-r--r--src/plugins/projectexplorer/processstep.cpp9
-rw-r--r--src/plugins/projectexplorer/projectexplorer.pro2
-rw-r--r--src/plugins/projectexplorer/projectexplorer.qbs1
-rw-r--r--src/plugins/projectexplorer/toolchain.h5
-rw-r--r--src/plugins/projectexplorer/toolchainsettingsaccessor.cpp2
-rw-r--r--src/plugins/projectexplorer/xcodebuildparser.cpp14
-rw-r--r--src/plugins/projectexplorer/xcodebuildparser.h2
-rw-r--r--src/plugins/python/pythonrunconfiguration.cpp6
-rw-r--r--src/plugins/qbsprojectmanager/qbsbuildstep.cpp33
-rw-r--r--src/plugins/qbsprojectmanager/qbsbuildstep.h3
-rw-r--r--src/plugins/qbsprojectmanager/qbscleanstep.cpp2
-rw-r--r--src/plugins/qbsprojectmanager/qbsinstallstep.cpp3
-rw-r--r--src/plugins/qmakeprojectmanager/qmakemakestep.cpp43
-rw-r--r--src/plugins/qmakeprojectmanager/qmakemakestep.h1
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeparser.cpp25
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeparser.h2
-rw-r--r--src/plugins/qmakeprojectmanager/qmakestep.cpp13
-rw-r--r--src/plugins/qmakeprojectmanager/qmakestep.h2
-rw-r--r--src/plugins/qtsupport/qtkitinformation.cpp2
-rw-r--r--src/plugins/qtsupport/qtkitinformation.h2
-rw-r--r--src/plugins/qtsupport/qtoutputformatter.cpp8
-rw-r--r--src/plugins/qtsupport/qtparser.cpp53
-rw-r--r--src/plugins/qtsupport/qtparser.h4
-rw-r--r--src/plugins/qtsupport/qttestparser.cpp9
-rw-r--r--src/plugins/qtsupport/qttestparser.h2
-rw-r--r--src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp4
-rw-r--r--src/plugins/vcsbase/vcsoutputformatter.h2
-rw-r--r--src/plugins/winrt/winrtpackagedeploymentstep.cpp4
110 files changed, 690 insertions, 1127 deletions
diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp
index 3112d22ae5..7bb6bbc464 100644
--- a/src/plugins/android/androidbuildapkstep.cpp
+++ b/src/plugins/android/androidbuildapkstep.cpp
@@ -178,22 +178,6 @@ bool AndroidBuildApkStep::init()
return false;
}
- auto parser = new JavaParser;
- parser->setProjectFileList(Utils::transform(target()->project()->files(ProjectExplorer::Project::AllFiles),
- &Utils::FilePath::toString));
-
- const QString buildKey = target()->activeBuildKey();
- const ProjectNode *node = target()->project()->findNodeForBuildKey(buildKey);
-
- QString sourceDirName;
- if (node)
- sourceDirName = node->data(Constants::AndroidPackageSourceDir).toString();
-
- QFileInfo sourceDirInfo(sourceDirName);
- parser->setSourceDirectory(Utils::FilePath::fromString(sourceDirInfo.canonicalFilePath()));
- parser->setBuildDirectory(buildDirectory().pathAppended(Constants::ANDROID_BUILDDIRECTORY));
- setOutputParser(parser);
-
m_openPackageLocationForRun = m_openPackageLocation;
if (m_buildAAB) {
@@ -218,6 +202,8 @@ bool AndroidBuildApkStep::init()
QString outputDir = buildDirectory().pathAppended(Constants::ANDROID_BUILDDIRECTORY).toString();
+ const QString buildKey = target()->activeBuildKey();
+ const ProjectNode *node = project()->findNodeForBuildKey(buildKey);
if (node)
m_inputFile = node->data(Constants::AndroidDeploySettingsFile).toString();
@@ -285,6 +271,23 @@ bool AndroidBuildApkStep::init()
return true;
}
+void AndroidBuildApkStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ const auto parser = new JavaParser;
+ parser->setProjectFileList(Utils::transform(project()->files(ProjectExplorer::Project::AllFiles),
+ &Utils::FilePath::toString));
+ const QString buildKey = target()->activeBuildKey();
+ const ProjectNode *node = project()->findNodeForBuildKey(buildKey);
+ QString sourceDirName;
+ if (node)
+ sourceDirName = node->data(Constants::AndroidPackageSourceDir).toString();
+ QFileInfo sourceDirInfo(sourceDirName);
+ parser->setSourceDirectory(Utils::FilePath::fromString(sourceDirInfo.canonicalFilePath()));
+ parser->setBuildDirectory(buildDirectory().pathAppended(Constants::ANDROID_BUILDDIRECTORY));
+ formatter->addLineParser(parser);
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
void AndroidBuildApkStep::showInGraphicalShell()
{
Core::FileUtils::showInGraphicalShell(Core::ICore::mainWindow(), m_packagePath);
diff --git a/src/plugins/android/androidbuildapkstep.h b/src/plugins/android/androidbuildapkstep.h
index e60d2b7f38..ab65a2d7f5 100644
--- a/src/plugins/android/androidbuildapkstep.h
+++ b/src/plugins/android/androidbuildapkstep.h
@@ -82,6 +82,7 @@ private:
void showInGraphicalShell();
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void processStarted() override;
void processFinished(int exitCode, QProcess::ExitStatus status) override;
diff --git a/src/plugins/android/androidpackageinstallationstep.cpp b/src/plugins/android/androidpackageinstallationstep.cpp
index 9fd25e9296..b16a8e864e 100644
--- a/src/plugins/android/androidpackageinstallationstep.cpp
+++ b/src/plugins/android/androidpackageinstallationstep.cpp
@@ -60,6 +60,7 @@ public:
private:
bool init() final;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
void doRun() final;
QStringList m_androidDirsToClean;
@@ -111,10 +112,6 @@ bool AndroidPackageInstallationStep::init()
pp->setEnvironment(env);
pp->setCommandLine(cmd);
- setOutputParser(new GnuMakeParser());
- appendOutputParsers(target()->kit()->createOutputParsers());
- outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
-
m_androidDirsToClean.clear();
// don't remove gradle's cache, it takes ages to rebuild it.
m_androidDirsToClean << dirPath + "/assets";
@@ -123,6 +120,14 @@ bool AndroidPackageInstallationStep::init()
return AbstractProcessStep::init();
}
+void AndroidPackageInstallationStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->addLineParser(new GnuMakeParser);
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
void AndroidPackageInstallationStep::doRun()
{
QString error;
diff --git a/src/plugins/android/javaparser.cpp b/src/plugins/android/javaparser.cpp
index 9cf3478953..04035c851d 100644
--- a/src/plugins/android/javaparser.cpp
+++ b/src/plugins/android/javaparser.cpp
@@ -51,7 +51,8 @@ void JavaParser::setSourceDirectory(const Utils::FilePath &sourceDirectory)
m_sourceDirectory = sourceDirectory;
}
-OutputTaskParser::Status JavaParser::handleLine(const QString &line, Utils::OutputFormat type)
+Utils::OutputLineParser::Result JavaParser::handleLine(const QString &line,
+ Utils::OutputFormat type)
{
Q_UNUSED(type);
if (m_javaRegExp.indexIn(line) == -1)
@@ -78,6 +79,8 @@ OutputTaskParser::Status JavaParser::handleLine(const QString &line, Utils::Outp
m_javaRegExp.cap(4).trimmed(),
absoluteFilePath(file),
lineno);
- emit addTask(task, 1);
- return Status::Done;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, task.file, task.line, m_javaRegExp, 2);
+ scheduleTask(task, 1);
+ return {Status::Done, linkSpecs};
}
diff --git a/src/plugins/android/javaparser.h b/src/plugins/android/javaparser.h
index 31cccbe98c..09b19d5bdb 100644
--- a/src/plugins/android/javaparser.h
+++ b/src/plugins/android/javaparser.h
@@ -45,7 +45,7 @@ public:
void setSourceDirectory(const Utils::FilePath &sourceDirectory);
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(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 b30bb82f2b..5e8b97fa62 100644
--- a/src/plugins/baremetal/iarewparser.cpp
+++ b/src/plugins/baremetal/iarewparser.cpp
@@ -145,12 +145,12 @@ bool IarParser::parseErrorOrFatalErrorDetailsMessage2(const QString &lne)
return true;
}
-bool IarParser::parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &lne)
+OutputLineParser::Result IarParser::parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &lne)
{
const QRegularExpression re("^\"(.+)\",(\\d+)?\\s+(Warning|Error|Fatal error)\\[(.+)\\].+$");
const QRegularExpressionMatch match = re.match(lne);
if (!match.hasMatch())
- return false;
+ return Status::NotHandled;
enum CaptureIndex { FilePathIndex = 1, LineNumberIndex,
MessageTypeIndex, MessageCodeIndex };
const Utils::FilePath fileName = Utils::FilePath::fromUserInput(
@@ -164,7 +164,10 @@ bool IarParser::parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &ln
m_expectDescription = true;
m_expectSnippet = false;
m_expectFilePath = false;
- return true;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match,
+ FilePathIndex);
+ return {Status::InProgress, linkSpecs};
}
bool IarParser::parseErrorInCommandLineMessage(const QString &lne)
@@ -190,7 +193,7 @@ bool IarParser::parseErrorMessage1(const QString &lne)
return true;
}
-OutputTaskParser::Status IarParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result IarParser::handleLine(const QString &line, OutputFormat type)
{
const QString lne = rightTrimmed(line);
if (type == StdOutFormat) {
@@ -208,8 +211,9 @@ OutputTaskParser::Status IarParser::handleLine(const QString &line, OutputFormat
return Status::InProgress;
if (parseErrorOrFatalErrorDetailsMessage2(lne))
return Status::InProgress;
- if (parseWarningOrErrorOrFatalErrorDetailsMessage1(lne))
- return Status::InProgress;
+ const Result res = parseWarningOrErrorOrFatalErrorDetailsMessage1(lne);
+ if (res.status != Status::NotHandled)
+ return res;
if (m_expectFilePath) {
if (lne.endsWith(']')) {
@@ -256,7 +260,7 @@ void IarParser::flush()
Task t = m_lastTask;
m_lastTask.clear();
- emit addTask(t, m_lines, 1);
+ scheduleTask(t, m_lines, 1);
m_lines = 0;
}
diff --git a/src/plugins/baremetal/iarewparser.h b/src/plugins/baremetal/iarewparser.h
index 02ad25062d..92b38bd26f 100644
--- a/src/plugins/baremetal/iarewparser.h
+++ b/src/plugins/baremetal/iarewparser.h
@@ -48,11 +48,11 @@ private:
bool parseErrorOrFatalErrorDetailsMessage1(const QString &lne);
bool parseErrorOrFatalErrorDetailsMessage2(const QString &lne);
- bool parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &lne);
+ Result parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &lne);
bool parseErrorInCommandLineMessage(const QString &lne);
bool parseErrorMessage1(const QString &lne);
- Status handleLine(const QString &line, Utils::OutputFormat type) final;
+ Result handleLine(const QString &line, Utils::OutputFormat type) final;
void flush() final;
ProjectExplorer::Task m_lastTask;
diff --git a/src/plugins/baremetal/iarewtoolchain.cpp b/src/plugins/baremetal/iarewtoolchain.cpp
index b65ebf0d9c..1ea9d013fe 100644
--- a/src/plugins/baremetal/iarewtoolchain.cpp
+++ b/src/plugins/baremetal/iarewtoolchain.cpp
@@ -354,7 +354,7 @@ void IarToolChain::addToEnvironment(Environment &env) const
}
}
-QList<OutputTaskParser *> IarToolChain::createOutputParsers() const
+QList<Utils::OutputLineParser *> IarToolChain::createOutputParsers() const
{
return {new IarParser()};
}
diff --git a/src/plugins/baremetal/iarewtoolchain.h b/src/plugins/baremetal/iarewtoolchain.h
index b1706ab2ac..82442f1817 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;
- QList<ProjectExplorer::OutputTaskParser *> createOutputParsers() const final;
+ QList<Utils::OutputLineParser *> createOutputParsers() 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 094e59ab0f..3e5032566b 100644
--- a/src/plugins/baremetal/keilparser.cpp
+++ b/src/plugins/baremetal/keilparser.cpp
@@ -93,12 +93,12 @@ void KeilParser::amendDescription()
// ARM compiler specific parsers.
-bool KeilParser::parseArmWarningOrErrorDetailsMessage(const QString &lne)
+OutputLineParser::Result KeilParser::parseArmWarningOrErrorDetailsMessage(const QString &lne)
{
const QRegularExpression re("^\"(.+)\", line (\\d+).*:\\s+(Warning|Error):(\\s+|.+)([#|L].+)$");
const QRegularExpressionMatch match = re.match(lne);
if (!match.hasMatch())
- return false;
+ return Status::NotHandled;
enum CaptureIndex { FilePathIndex = 1, LineNumberIndex,
MessageTypeIndex, MessageNoteIndex, DescriptionIndex };
const Utils::FilePath fileName = Utils::FilePath::fromUserInput(
@@ -107,7 +107,10 @@ bool KeilParser::parseArmWarningOrErrorDetailsMessage(const QString &lne)
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
const QString descr = match.captured(DescriptionIndex);
newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
- return true;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match,
+ FilePathIndex);
+ return {Status::InProgress, linkSpecs};
}
bool KeilParser::parseArmErrorOrFatalErorrMessage(const QString &lne)
@@ -125,12 +128,12 @@ bool KeilParser::parseArmErrorOrFatalErorrMessage(const QString &lne)
// MCS51 compiler specific parsers.
-bool KeilParser::parseMcs51WarningOrErrorDetailsMessage1(const QString &lne)
+OutputLineParser::Result KeilParser::parseMcs51WarningOrErrorDetailsMessage1(const QString &lne)
{
const QRegularExpression re("^\\*{3} (WARNING|ERROR) (\\w+) IN LINE (\\d+) OF (.+\\.\\S+): (.+)$");
const QRegularExpressionMatch match = re.match(lne);
if (!match.hasMatch())
- return false;
+ return Status::NotHandled;
enum CaptureIndex { MessageTypeIndex = 1, MessageCodeIndex, LineNumberIndex,
FilePathIndex, MessageTextIndex };
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
@@ -140,15 +143,18 @@ bool KeilParser::parseMcs51WarningOrErrorDetailsMessage1(const QString &lne)
const QString descr = QString("%1: %2").arg(match.captured(MessageCodeIndex),
match.captured(MessageTextIndex));
newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
- return true;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match,
+ FilePathIndex);
+ return {Status::InProgress, linkSpecs};
}
-bool KeilParser::parseMcs51WarningOrErrorDetailsMessage2(const QString &lne)
+OutputLineParser::Result KeilParser::parseMcs51WarningOrErrorDetailsMessage2(const QString &lne)
{
const QRegularExpression re("^\\*{3} (WARNING|ERROR) (#\\w+) IN (\\d+) \\((.+), LINE \\d+\\): (.+)$");
const QRegularExpressionMatch match = re.match(lne);
if (!match.hasMatch())
- return false;
+ return Status::NotHandled;
enum CaptureIndex { MessageTypeIndex = 1, MessageCodeIndex, LineNumberIndex,
FilePathIndex, MessageTextIndex };
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
@@ -158,7 +164,10 @@ bool KeilParser::parseMcs51WarningOrErrorDetailsMessage2(const QString &lne)
const QString descr = QString("%1: %2").arg(match.captured(MessageCodeIndex),
match.captured(MessageTextIndex));
newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
- return true;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match,
+ FilePathIndex);
+ return {Status::InProgress, linkSpecs};
}
bool KeilParser::parseMcs51WarningOrFatalErrorMessage(const QString &lne)
@@ -206,15 +215,17 @@ static bool hasDetailsPointer(const QString &trimmedLine)
return trimmedLine.contains('_');
}
-OutputTaskParser::Status KeilParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result KeilParser::handleLine(const QString &line, OutputFormat type)
{
QString lne = rightTrimmed(line);
if (type == StdOutFormat) {
// Check for MSC51 compiler specific patterns.
- const bool parsed = parseMcs51WarningOrErrorDetailsMessage1(lne)
- || parseMcs51WarningOrErrorDetailsMessage2(lne);
- if (parsed)
- return Status::InProgress;
+ Result res = parseMcs51WarningOrErrorDetailsMessage1(lne);
+ if (res.status != Status::NotHandled)
+ return res;
+ res = parseMcs51WarningOrErrorDetailsMessage2(lne);
+ if (res.status != Status::NotHandled)
+ return res;
if (parseMcs51WarningOrFatalErrorMessage(lne))
return Status::InProgress;
if (parseMcs51FatalErrorMessage2(lne))
@@ -247,8 +258,9 @@ OutputTaskParser::Status KeilParser::handleLine(const QString &line, OutputForma
}
// Check for ARM compiler specific patterns.
- if (parseArmWarningOrErrorDetailsMessage(lne))
- return Status::InProgress;
+ const Result res = parseArmWarningOrErrorDetailsMessage(lne);
+ if (res.status != Status::NotHandled)
+ return res;
if (parseArmErrorOrFatalErorrMessage(lne))
return Status::InProgress;
@@ -270,7 +282,7 @@ void KeilParser::flush()
Task t = m_lastTask;
m_lastTask.clear();
- emit addTask(t, m_lines, 1);
+ scheduleTask(t, m_lines, 1);
m_lines = 0;
}
diff --git a/src/plugins/baremetal/keilparser.h b/src/plugins/baremetal/keilparser.h
index d717e74453..f8f5f8b97d 100644
--- a/src/plugins/baremetal/keilparser.h
+++ b/src/plugins/baremetal/keilparser.h
@@ -46,16 +46,16 @@ private:
void amendDescription();
// ARM compiler specific parsers.
- bool parseArmWarningOrErrorDetailsMessage(const QString &lne);
+ Result parseArmWarningOrErrorDetailsMessage(const QString &lne);
bool parseArmErrorOrFatalErorrMessage(const QString &lne);
// MCS51 compiler specific parsers.
- bool parseMcs51WarningOrErrorDetailsMessage1(const QString &lne);
- bool parseMcs51WarningOrErrorDetailsMessage2(const QString &lne);
+ Result parseMcs51WarningOrErrorDetailsMessage1(const QString &lne);
+ Result parseMcs51WarningOrErrorDetailsMessage2(const QString &lne);
bool parseMcs51WarningOrFatalErrorMessage(const QString &lne);
bool parseMcs51FatalErrorMessage2(const QString &lne);
- Status handleLine(const QString &line, Utils::OutputFormat type) final;
+ Result handleLine(const QString &line, Utils::OutputFormat type) final;
void flush() final;
ProjectExplorer::Task m_lastTask;
diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp
index 922d38a401..3eca05dcc6 100644
--- a/src/plugins/baremetal/keiltoolchain.cpp
+++ b/src/plugins/baremetal/keiltoolchain.cpp
@@ -506,7 +506,7 @@ void KeilToolChain::addToEnvironment(Environment &env) const
}
}
-QList<OutputTaskParser *> KeilToolChain::createOutputParsers() const
+QList<OutputLineParser *> KeilToolChain::createOutputParsers() const
{
return {new KeilParser};
}
diff --git a/src/plugins/baremetal/keiltoolchain.h b/src/plugins/baremetal/keiltoolchain.h
index 561db08bd1..3fd36d6796 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;
- QList<ProjectExplorer::OutputTaskParser *> createOutputParsers() const final;
+ QList<Utils::OutputLineParser *> createOutputParsers() 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 7cfd363d74..9ed21234d9 100644
--- a/src/plugins/baremetal/sdccparser.cpp
+++ b/src/plugins/baremetal/sdccparser.cpp
@@ -87,7 +87,7 @@ void SdccParser::amendDescription(const QString &desc)
++m_lines;
}
-OutputTaskParser::Status SdccParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result SdccParser::handleLine(const QString &line, OutputFormat type)
{
if (type == StdOutFormat)
return Status::NotHandled;
@@ -108,7 +108,10 @@ OutputTaskParser::Status SdccParser::handleLine(const QString &line, OutputForma
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
const QString descr = match.captured(MessageTextIndex);
newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
- return Status::InProgress;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match,
+ FilePathIndex);
+ return {Status::InProgress, linkSpecs};
}
re.setPattern("^(.+\\.\\S+):(\\d+): (Error|error|syntax error): (.+)$");
@@ -122,7 +125,10 @@ OutputTaskParser::Status SdccParser::handleLine(const QString &line, OutputForma
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
const QString descr = match.captured(MessageTextIndex);
newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
- return Status::InProgress;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match,
+ FilePathIndex);
+ return {Status::InProgress, linkSpecs};
}
re.setPattern("^at (\\d+): (warning|error) \\d+: (.+)$");
@@ -161,7 +167,7 @@ void SdccParser::flush()
Task t = m_lastTask;
m_lastTask.clear();
- emit addTask(t, m_lines, 1);
+ scheduleTask(t, m_lines, 1);
m_lines = 0;
}
diff --git a/src/plugins/baremetal/sdccparser.h b/src/plugins/baremetal/sdccparser.h
index a8b6f2c0fd..0b92b70225 100644
--- a/src/plugins/baremetal/sdccparser.h
+++ b/src/plugins/baremetal/sdccparser.h
@@ -45,7 +45,7 @@ private:
void newTask(const ProjectExplorer::Task &task);
void amendDescription(const QString &desc);
- Status handleLine(const QString &line, Utils::OutputFormat type) final;
+ Result handleLine(const QString &line, Utils::OutputFormat type) final;
void flush() final;
ProjectExplorer::Task m_lastTask;
diff --git a/src/plugins/baremetal/sdcctoolchain.cpp b/src/plugins/baremetal/sdcctoolchain.cpp
index 0039b32f21..36bc7945bb 100644
--- a/src/plugins/baremetal/sdcctoolchain.cpp
+++ b/src/plugins/baremetal/sdcctoolchain.cpp
@@ -307,7 +307,7 @@ void SdccToolChain::addToEnvironment(Environment &env) const
}
}
-QList<OutputTaskParser *> SdccToolChain::createOutputParsers() const
+QList<Utils::OutputLineParser *> SdccToolChain::createOutputParsers() const
{
return {new SdccParser};
}
diff --git a/src/plugins/baremetal/sdcctoolchain.h b/src/plugins/baremetal/sdcctoolchain.h
index 0ac575c982..09aff331af 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;
- QList<ProjectExplorer::OutputTaskParser *> createOutputParsers() const final;
+ QList<Utils::OutputLineParser *> createOutputParsers() 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 0ece524c19..aa9c3f6e6e 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
@@ -197,16 +197,19 @@ bool CMakeBuildStep::init()
pp->setCommandLine(cmakeCommand(rc));
pp->resolveAll();
- CMakeParser *cmakeParser = new CMakeParser;
- cmakeParser->setSourceDirectory(projectDirectory.toString());
- setOutputParser(cmakeParser);
- appendOutputParser(new GnuMakeParser);
- appendOutputParsers(target()->kit()->createOutputParsers());
- outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
-
return AbstractProcessStep::init();
}
+void CMakeBuildStep::setupOutputFormatter(Utils::OutputFormatter *formatter)
+{
+ CMakeParser *cmakeParser = new CMakeParser;
+ cmakeParser->setSourceDirectory(project()->projectDirectory().toString());
+ formatter->addLineParsers({cmakeParser, new GnuMakeParser});
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
void CMakeBuildStep::doRun()
{
// Make sure CMake state was written to disk before trying to build:
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.h b/src/plugins/cmakeprojectmanager/cmakebuildstep.h
index cd41f77f41..1e5a4e7100 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildstep.h
+++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.h
@@ -83,6 +83,7 @@ private:
void ctor(ProjectExplorer::BuildStepList *bsl);
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
void doRun() override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
diff --git a/src/plugins/cmakeprojectmanager/cmakeparser.cpp b/src/plugins/cmakeprojectmanager/cmakeparser.cpp
index a2dba99b1c..2d8aa7c022 100644
--- a/src/plugins/cmakeprojectmanager/cmakeparser.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeparser.cpp
@@ -54,10 +54,13 @@ CMakeParser::CMakeParser()
void CMakeParser::setSourceDirectory(const QString &sourceDir)
{
+ if (m_sourceDirectory)
+ emit searchDirExpired(FilePath::fromString(m_sourceDirectory.value().path()));
m_sourceDirectory = QDir(sourceDir);
+ emit addSearchDir(FilePath::fromString(sourceDir));
}
-OutputTaskParser::Status CMakeParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result CMakeParser::handleLine(const QString &line, OutputFormat type)
{
if (type != StdErrFormat)
return Status::NotHandled;
@@ -80,18 +83,23 @@ OutputTaskParser::Status CMakeParser::handleLine(const QString &line, OutputForm
QString path = m_sourceDirectory ? m_sourceDirectory->absoluteFilePath(
QDir::fromNativeSeparators(m_commonError.cap(1)))
: QDir::fromNativeSeparators(m_commonError.cap(1));
-
m_lastTask = BuildSystemTask(Task::Error,
QString(),
absoluteFilePath(FilePath::fromUserInput(path)),
m_commonError.cap(2).toInt());
m_lines = 1;
- return Status::InProgress;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line,
+ m_commonError, 1);
+ return {Status::InProgress, linkSpecs};
} else if (m_nextSubError.indexIn(trimmedLine) != -1) {
m_lastTask = BuildSystemTask(Task::Error, QString(),
absoluteFilePath(FilePath::fromUserInput(m_nextSubError.cap(1))));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line,
+ m_nextSubError, 1);
m_lines = 1;
- return Status::InProgress;
+ return {Status::InProgress, linkSpecs};
} else if (trimmedLine.startsWith(QLatin1String(" ")) && !m_lastTask.isNull()) {
if (!m_lastTask.description.isEmpty())
m_lastTask.description.append(QLatin1Char(' '));
@@ -118,11 +126,15 @@ OutputTaskParser::Status CMakeParser::handleLine(const QString &line, OutputForm
{
QRegularExpressionMatch m = m_locationLine.match(trimmedLine);
QTC_CHECK(m.hasMatch());
- m_lastTask.file = Utils::FilePath::fromUserInput(trimmedLine.mid(0, m.capturedStart()));
+ m_lastTask.file = absoluteFilePath(FilePath::fromUserInput(
+ trimmedLine.mid(0, m.capturedStart())));
m_lastTask.line = m.captured(1).toInt();
m_expectTripleLineErrorData = LINE_DESCRIPTION;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, 0,
+ m.capturedStart());
+ return {Status::InProgress, linkSpecs};
}
- return Status::InProgress;
case LINE_DESCRIPTION:
m_lastTask.description = trimmedLine;
if (trimmedLine.endsWith(QLatin1Char('\"')))
@@ -149,7 +161,7 @@ void CMakeParser::flush()
return;
Task t = m_lastTask;
m_lastTask.clear();
- emit addTask(t, m_lines, 1);
+ scheduleTask(t, m_lines, 1);
m_lines = 0;
}
diff --git a/src/plugins/cmakeprojectmanager/cmakeparser.h b/src/plugins/cmakeprojectmanager/cmakeparser.h
index dfcf6d0c1b..b0cfc6f55a 100644
--- a/src/plugins/cmakeprojectmanager/cmakeparser.h
+++ b/src/plugins/cmakeprojectmanager/cmakeparser.h
@@ -47,7 +47,7 @@ public:
void setSourceDirectory(const QString &sourceDir);
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
void flush() override;
enum TripleLineError { NONE, LINE_LOCATION, LINE_DESCRIPTION, LINE_DESCRIPTION2 };
diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp
index 0e6d7a52ff..e500ac8c2e 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp
@@ -94,17 +94,6 @@ void CMakeProcess::run(const BuildDirParameters &parameters, const QStringList &
const auto parser = new CMakeParser;
parser->setSourceDirectory(srcDir);
m_parser.addLineParser(parser);
- QDir source = QDir(srcDir);
- connect(&m_parser, &IOutputParser::addTask, this,
- [source](const Task &task) {
- if (task.file.isEmpty() || task.file.toFileInfo().isAbsolute()) {
- TaskHub::addTask(task);
- } else {
- Task t = task;
- t.file = Utils::FilePath::fromString(source.absoluteFilePath(task.file.toString()));
- TaskHub::addTask(t);
- }
- });
// Always use the sourceDir: If we are triggered because the build directory is getting deleted
// then we are racing against CMakeCache.txt also getting deleted.
@@ -194,7 +183,7 @@ void CMakeProcess::processStandardError()
static QString rest;
rest = lineSplit(rest, m_process->readAllStandardError(), [this](const QString &s) {
- m_parser.handleStderr(s);
+ m_parser.appendMessage(s, Utils::StdErrFormat);
Core::MessageManager::write(s);
});
}
diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.h b/src/plugins/cmakeprojectmanager/cmakeprocess.h
index ed68f9f96c..c63f54952a 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprocess.h
+++ b/src/plugins/cmakeprojectmanager/cmakeprocess.h
@@ -27,8 +27,7 @@
#include "builddirparameters.h"
-#include <projectexplorer/ioutputparser.h>
-
+#include <utils/outputformatter.h>
#include <utils/qtcprocess.h>
#include <QElapsedTimer>
@@ -72,7 +71,7 @@ private:
void checkForCancelled();
std::unique_ptr<Utils::QtcProcess> m_process;
- ProjectExplorer::IOutputParser m_parser;
+ Utils::OutputFormatter m_parser;
std::unique_ptr<QFutureInterface<void>> m_future;
bool m_processWasCanceled = false;
QTimer m_cancelTimer;
diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp
index 85ead8eadd..e9f9f99426 100644
--- a/src/plugins/cmakeprojectmanager/servermodereader.cpp
+++ b/src/plugins/cmakeprojectmanager/servermodereader.cpp
@@ -64,14 +64,6 @@ ServerModeReader::ServerModeReader()
{
m_cmakeParser = new CMakeParser;
m_parser.addLineParser(m_cmakeParser);
- connect(&m_parser, &IOutputParser::addTask, this, [this](const Task &t) {
- Task editable(t);
- if (!editable.file.isEmpty()) {
- QDir srcDir(m_parameters.sourceDirectory.toString());
- editable.file = FilePath::fromString(srcDir.absoluteFilePath(editable.file.toString()));
- }
- TaskHub::addTask(editable);
- });
}
ServerModeReader::~ServerModeReader()
@@ -351,7 +343,7 @@ void ServerModeReader::createNewServer()
connect(m_cmakeServer.get(), &ServerMode::cmakeMessage, [this](const QString &m) {
const QStringList lines = m.split('\n');
for (const QString &l : lines) {
- m_parser.handleStderr(l);
+ m_parser.appendMessage(l, StdErrFormat);
Core::MessageManager::write(l);
}
});
diff --git a/src/plugins/cmakeprojectmanager/servermodereader.h b/src/plugins/cmakeprojectmanager/servermodereader.h
index a93b91e6fa..66ab0a56be 100644
--- a/src/plugins/cmakeprojectmanager/servermodereader.h
+++ b/src/plugins/cmakeprojectmanager/servermodereader.h
@@ -37,6 +37,7 @@
#include <memory>
namespace ProjectExplorer { class ProjectNode; }
+namespace Utils { class OutputFormatter; }
namespace CMakeProjectManager {
@@ -187,7 +188,7 @@ private:
QList<FileGroup *> m_fileGroups;
CMakeParser *m_cmakeParser = nullptr;
- ProjectExplorer::IOutputParser m_parser;
+ Utils::OutputFormatter m_parser;
#if defined(WITH_TESTS)
friend class CMakeProjectPlugin;
diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp
index 91504ff1a1..b27b91afc0 100644
--- a/src/plugins/coreplugin/outputwindow.cpp
+++ b/src/plugins/coreplugin/outputwindow.cpp
@@ -26,6 +26,7 @@
#include "outputwindow.h"
#include "actionmanager/actionmanager.h"
+#include "editormanager/editormanager.h"
#include "coreconstants.h"
#include "coreplugin.h"
#include "icore.h"
@@ -138,6 +139,11 @@ OutputWindow::OutputWindow(Context context, const QString &settingsKey, QWidget
Core::ICore::settings()->setValue(d->settingsKey, fontZoom());
});
+ connect(outputFormatter(), &OutputFormatter::openInEditorRequested, this,
+ [](const Utils::FilePath &fp, int line, int column) {
+ EditorManager::openEditorAt(fp.toString(), line, column);
+ });
+
undoAction->setEnabled(false);
redoAction->setEnabled(false);
cutAction->setEnabled(false);
@@ -528,12 +534,10 @@ private:
return Status::NotHandled;
}
- void reset() override { m_handling = false; }
-
bool m_handling = false;
};
-// Handles all lines starting with "B". No continuation logic
+// Handles all lines starting with "B". No continuation logic.
class TestFormatterB : public OutputLineParser
{
private:
@@ -571,18 +575,17 @@ void Internal::CorePlugin::testOutputFormatter()
" A trick\n"
" embedded carriage return\n"
"handled by B\n";
- OutputFormatter formatter;
- QPlainTextEdit textEdit;
- formatter.setPlainTextEdit(&textEdit);
- formatter.setLineParsers({new TestFormatterB, new TestFormatterA});
// Stress-test the implementation by providing the input in chunks, splitting at all possible
// offsets.
for (int i = 0; i < input.length(); ++i) {
- formatter.appendMessage(input.left(i), NormalMessageFormat);
- formatter.appendMessage(input.mid(i), NormalMessageFormat);
+ OutputFormatter formatter;
+ QPlainTextEdit textEdit;
+ formatter.setPlainTextEdit(&textEdit);
+ formatter.setLineParsers({new TestFormatterB, new TestFormatterA});
+ formatter.appendMessage(input.left(i), StdOutFormat);
+ formatter.appendMessage(input.mid(i), StdOutFormat);
QCOMPARE(textEdit.toPlainText(), output);
- formatter.clear();
}
}
#endif // WITH_TESTS
diff --git a/src/plugins/ios/iosbuildstep.cpp b/src/plugins/ios/iosbuildstep.cpp
index a8503d0fc6..9fbe292299 100644
--- a/src/plugins/ios/iosbuildstep.cpp
+++ b/src/plugins/ios/iosbuildstep.cpp
@@ -82,6 +82,7 @@ public:
Utils::FilePath buildCommand() const;
bool init() final;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter);
void doRun() final;
bool fromMap(const QVariantMap &map) final;
QVariantMap toMap() const final;
@@ -222,13 +223,17 @@ bool IosBuildStep::init()
// That is mostly so that rebuild works on an already clean project
setIgnoreReturnValue(m_clean);
- setOutputParser(new GnuMakeParser());
- appendOutputParsers(target()->kit()->createOutputParsers());
- outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
-
return AbstractProcessStep::init();
}
+void IosBuildStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->addLineParser(new GnuMakeParser);
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
QVariantMap IosBuildStep::toMap() const
{
QVariantMap map(AbstractProcessStep::toMap());
diff --git a/src/plugins/ios/iosdsymbuildstep.cpp b/src/plugins/ios/iosdsymbuildstep.cpp
index f188630bc6..3b11d06922 100644
--- a/src/plugins/ios/iosdsymbuildstep.cpp
+++ b/src/plugins/ios/iosdsymbuildstep.cpp
@@ -80,9 +80,6 @@ bool IosDsymBuildStep::init()
// That is mostly so that rebuild works on an already clean project
setIgnoreReturnValue(m_clean);
- appendOutputParsers(target()->kit()->createOutputParsers());
- outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
-
return AbstractProcessStep::init();
}
@@ -189,6 +186,13 @@ void IosDsymBuildStep::doRun()
AbstractProcessStep::doRun();
}
+void IosDsymBuildStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->setLineParsers(target()->kit()->createOutputParsers());
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
BuildStepConfigWidget *IosDsymBuildStep::createConfigWidget()
{
return new IosDsymBuildStepConfigWidget(this);
diff --git a/src/plugins/ios/iosdsymbuildstep.h b/src/plugins/ios/iosdsymbuildstep.h
index effc6e5f91..7e08b1a6ad 100644
--- a/src/plugins/ios/iosdsymbuildstep.h
+++ b/src/plugins/ios/iosdsymbuildstep.h
@@ -56,6 +56,7 @@ public:
private:
bool init() override;
void doRun() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
QVariantMap toMap() const override;
bool fromMap(const QVariantMap &map) override;
diff --git a/src/plugins/nim/project/nimblebuildstep.cpp b/src/plugins/nim/project/nimblebuildstep.cpp
index 7beebc7ae9..1d29fbb1aa 100644
--- a/src/plugins/nim/project/nimblebuildstep.cpp
+++ b/src/plugins/nim/project/nimblebuildstep.cpp
@@ -45,7 +45,7 @@ namespace {
class NimParser : public OutputTaskParser
{
- Status handleLine(const QString &lne, Utils::OutputFormat) override
+ Result handleLine(const QString &lne, Utils::OutputFormat) override
{
const QString line = lne.trimmed();
static QRegularExpression regex("(.+.nim)\\((\\d+), (\\d+)\\) (.+)",
@@ -74,9 +74,12 @@ class NimParser : public OutputTaskParser
else
return Status::NotHandled;
- emit addTask(CompileTask(type, message, absoluteFilePath(FilePath::fromUserInput(filename)),
- lineNumber));
- return Status::Done;
+ const CompileTask t(type, message, absoluteFilePath(FilePath::fromUserInput(filename)),
+ lineNumber);
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, t.file, t.line, match, 1);
+ scheduleTask(t, 1);
+ return {Status::Done, linkSpecs};
}
};
@@ -95,10 +98,6 @@ NimbleBuildStep::NimbleBuildStep(BuildStepList *parentList, Core::Id id)
bool NimbleBuildStep::init()
{
- auto parser = new NimParser();
- parser->addSearchDir(project()->projectDirectory());
- setOutputParser(parser);
-
ProcessParameters* params = processParameters();
params->setEnvironment(buildEnvironment());
params->setMacroExpander(macroExpander());
@@ -107,6 +106,14 @@ bool NimbleBuildStep::init()
return AbstractProcessStep::init();
}
+void NimbleBuildStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ const auto parser = new NimParser();
+ parser->addSearchDir(project()->projectDirectory());
+ formatter->addLineParser(parser);
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
BuildStepConfigWidget *NimbleBuildStep::createConfigWidget()
{
return new NimbleBuildStepWidget(this);
diff --git a/src/plugins/nim/project/nimblebuildstep.h b/src/plugins/nim/project/nimblebuildstep.h
index 3a3af51046..7d903e5135 100644
--- a/src/plugins/nim/project/nimblebuildstep.h
+++ b/src/plugins/nim/project/nimblebuildstep.h
@@ -37,7 +37,7 @@ public:
NimbleBuildStep(ProjectExplorer::BuildStepList *parentList, Core::Id id);
bool init() override;
-
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
QString arguments() const;
diff --git a/src/plugins/nim/project/nimcompilerbuildstep.cpp b/src/plugins/nim/project/nimcompilerbuildstep.cpp
index 4950f20fbb..9015a2002d 100644
--- a/src/plugins/nim/project/nimcompilerbuildstep.cpp
+++ b/src/plugins/nim/project/nimcompilerbuildstep.cpp
@@ -47,7 +47,7 @@ namespace Nim {
class NimParser : public ProjectExplorer::OutputTaskParser
{
- Status handleLine(const QString &lne, Utils::OutputFormat) override
+ Result handleLine(const QString &lne, Utils::OutputFormat) override
{
const QString line = lne.trimmed();
static QRegularExpression regex("(.+.nim)\\((\\d+), (\\d+)\\) (.+)",
@@ -76,9 +76,12 @@ class NimParser : public ProjectExplorer::OutputTaskParser
else
return Status::NotHandled;
- emit addTask(CompileTask(type, message, absoluteFilePath(FilePath::fromUserInput(filename)),
- lineNumber));
- return Status::Done;
+ const CompileTask t(type, message, absoluteFilePath(FilePath::fromUserInput(filename)),
+ lineNumber);
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, t.file, t.line, match, 1);
+ scheduleTask(t, 1);
+ return {Status::Done, linkSpecs};
}
};
@@ -100,12 +103,12 @@ NimCompilerBuildStep::NimCompilerBuildStep(BuildStepList *parentList, Core::Id i
updateProcessParameters();
}
-bool NimCompilerBuildStep::init()
+void NimCompilerBuildStep::setupOutputFormatter(OutputFormatter *formatter)
{
- setOutputParser(new NimParser());
- appendOutputParsers(target()->kit()->createOutputParsers());
- outputParser()->addSearchDir(processParameters()->effectiveWorkingDirectory());
- return AbstractProcessStep::init();
+ formatter->addLineParser(new NimParser);
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+ AbstractProcessStep::setupOutputFormatter(formatter);
}
BuildStepConfigWidget *NimCompilerBuildStep::createConfigWidget()
diff --git a/src/plugins/nim/project/nimcompilerbuildstep.h b/src/plugins/nim/project/nimcompilerbuildstep.h
index aca8750c06..cd194e06ea 100644
--- a/src/plugins/nim/project/nimcompilerbuildstep.h
+++ b/src/plugins/nim/project/nimcompilerbuildstep.h
@@ -41,7 +41,7 @@ public:
NimCompilerBuildStep(ProjectExplorer::BuildStepList *parentList, Core::Id id);
- bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
bool fromMap(const QVariantMap &map) override;
diff --git a/src/plugins/nim/project/nimtoolchain.cpp b/src/plugins/nim/project/nimtoolchain.cpp
index 337e697e4f..1d1cf4e1a7 100644
--- a/src/plugins/nim/project/nimtoolchain.cpp
+++ b/src/plugins/nim/project/nimtoolchain.cpp
@@ -120,7 +120,7 @@ void NimToolChain::setCompilerCommand(const FilePath &compilerCommand)
parseVersion(compilerCommand, m_version);
}
-QList<OutputTaskParser *> NimToolChain::createOutputParsers() const
+QList<Utils::OutputLineParser *> NimToolChain::createOutputParsers() const
{
return {};
}
diff --git a/src/plugins/nim/project/nimtoolchain.h b/src/plugins/nim/project/nimtoolchain.h
index 7ef119af1e..d61448e6a0 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);
- QList<ProjectExplorer::OutputTaskParser *> createOutputParsers() const final;
+ QList<Utils::OutputLineParser *> createOutputParsers() const final;
std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() final;
QVariantMap toMap() const final;
diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt
index 24b7dbd655..35ed62afc6 100644
--- a/src/plugins/projectexplorer/CMakeLists.txt
+++ b/src/plugins/projectexplorer/CMakeLists.txt
@@ -8,7 +8,6 @@ add_qtc_plugin(ProjectExplorer
addrunconfigdialog.cpp addrunconfigdialog.h
allprojectsfilter.cpp allprojectsfilter.h
allprojectsfind.cpp allprojectsfind.h
- ansifilterparser.cpp ansifilterparser.h
applicationlauncher.cpp applicationlauncher.h
appoutputpane.cpp appoutputpane.h
baseprojectwizarddialog.cpp baseprojectwizarddialog.h
diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp
index 479cd309f3..1a9d18a937 100644
--- a/src/plugins/projectexplorer/abstractprocessstep.cpp
+++ b/src/plugins/projectexplorer/abstractprocessstep.cpp
@@ -24,7 +24,6 @@
****************************************************************************/
#include "abstractprocessstep.h"
-#include "ansifilterparser.h"
#include "buildconfiguration.h"
#include "buildstep.h"
#include "ioutputparser.h"
@@ -37,8 +36,8 @@
#include <coreplugin/reaper.h>
-#include <utils/fileinprojectfinder.h>
#include <utils/fileutils.h>
+#include <utils/outputformatter.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
@@ -106,27 +105,18 @@ public:
AbstractProcessStep *q;
std::unique_ptr<Utils::QtcProcess> m_process;
- IOutputParser m_outputParser;
ProcessParameters m_param;
bool m_ignoreReturnValue = false;
bool m_lowPriority = false;
std::unique_ptr<QTextDecoder> stdoutStream;
std::unique_ptr<QTextDecoder> stderrStream;
+ OutputFormatter *outputFormatter = nullptr;
};
AbstractProcessStep::AbstractProcessStep(BuildStepList *bsl, Core::Id id) :
BuildStep(bsl, id),
d(new Private(this))
{
- connect(&d->m_outputParser, &IOutputParser::addTask, this,
- [this](const Task &task, int linkedLines, int skipLines) {
- // Do not bother to report issues if we do not care about the results of
- // the buildstep anyway:
- // TODO: Does that make sense? The user might still want to know that
- // something failed, even if it wasn't fatal...
- if (!d->m_ignoreReturnValue)
- emit addTask(task, linkedLines, skipLines);
- });
}
AbstractProcessStep::~AbstractProcessStep()
@@ -134,36 +124,6 @@ AbstractProcessStep::~AbstractProcessStep()
delete d;
}
-/*!
- Deletes all existing output parsers and starts a new chain with the
- given parser.
-*/
-void AbstractProcessStep::setOutputParser(OutputTaskParser *parser)
-{
- d->m_outputParser.setLineParsers({parser});
-}
-
-/*!
- Appends the given output parser to the existing chain of parsers.
-*/
-void AbstractProcessStep::appendOutputParser(OutputTaskParser *parser)
-{
- if (!parser)
- return;
- d->m_outputParser.addLineParser(parser);
-}
-
-void AbstractProcessStep::appendOutputParsers(const QList<OutputTaskParser *> &parsers)
-{
- for (OutputTaskParser * const p : parsers)
- appendOutputParser(p);
-}
-
-IOutputParser *AbstractProcessStep::outputParser() const
-{
- return &d->m_outputParser;
-}
-
void AbstractProcessStep::emitFaultyConfigurationMessage()
{
emit addOutput(tr("Configuration is faulty. Check the Issues view for details."),
@@ -194,14 +154,16 @@ void AbstractProcessStep::setIgnoreReturnValue(bool b)
bool AbstractProcessStep::init()
{
- Utils::FileInProjectFinder fileFinder;
- fileFinder.setProjectDirectory(project()->projectDirectory());
- fileFinder.setProjectFiles(project()->files(Project::AllFiles));
- d->m_outputParser.addFilter(&Internal::filterAnsiEscapeCodes);
- d->m_outputParser.setFileFinder(fileFinder);
return !d->m_process;
}
+void AbstractProcessStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->setDemoteErrorsToWarnings(d->m_ignoreReturnValue);
+ d->outputFormatter = formatter;
+ BuildStep::setupOutputFormatter(formatter);
+}
+
/*!
Reimplemented from BuildStep::init(). You need to call this from
YourBuildStep::run().
@@ -257,7 +219,6 @@ void AbstractProcessStep::doRun()
if (!d->m_process->waitForStarted()) {
processStartupFailed();
d->m_process.reset();
- d->m_outputParser.clear();
finish(false);
return;
}
@@ -285,7 +246,6 @@ void AbstractProcessStep::cleanUp(QProcess *process)
processFinished(process->exitCode(), process->exitStatus());
const bool returnValue = processSucceeded(process->exitCode(), process->exitStatus()) || d->m_ignoreReturnValue;
- d->m_outputParser.clear();
d->m_process.reset();
// Report result
@@ -315,9 +275,6 @@ void AbstractProcessStep::processStarted()
void AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus status)
{
- d->m_outputParser.flush();
- d->m_outputParser.clear();
-
QString command = QDir::toNativeSeparators(d->m_param.effectiveCommand().toString());
if (status == QProcess::NormalExit && exitCode == 0) {
emit addOutput(tr("The process \"%1\" exited normally.").arg(command),
@@ -351,7 +308,7 @@ void AbstractProcessStep::processStartupFailed()
bool AbstractProcessStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
{
- if (outputParser()->hasFatalErrors())
+ if (d->outputFormatter->hasFatalErrors())
return false;
return exitCode == 0 && status == QProcess::NormalExit;
@@ -372,7 +329,6 @@ void AbstractProcessStep::processReadyReadStdOutput()
void AbstractProcessStep::stdOutput(const QString &output)
{
- d->m_outputParser.handleStdout(output);
emit addOutput(output, BuildStep::OutputFormat::Stdout, BuildStep::DontAppendNewline);
}
@@ -391,7 +347,6 @@ void AbstractProcessStep::processReadyReadStdError()
void AbstractProcessStep::stdError(const QString &output)
{
- d->m_outputParser.handleStderr(output);
emit addOutput(output, BuildStep::OutputFormat::Stderr, BuildStep::DontAppendNewline);
}
diff --git a/src/plugins/projectexplorer/abstractprocessstep.h b/src/plugins/projectexplorer/abstractprocessstep.h
index f6b720eb13..9431c3a97c 100644
--- a/src/plugins/projectexplorer/abstractprocessstep.h
+++ b/src/plugins/projectexplorer/abstractprocessstep.h
@@ -31,8 +31,6 @@
namespace Utils { class FilePath; }
namespace ProjectExplorer {
-
-class IOutputParser;
class OutputTaskParser;
class ProcessParameters;
@@ -47,17 +45,13 @@ public:
bool ignoreReturnValue();
void setIgnoreReturnValue(bool b);
- void setOutputParser(OutputTaskParser *parser);
- void appendOutputParser(OutputTaskParser *parser);
- void appendOutputParsers(const QList<OutputTaskParser *> &parsers);
- IOutputParser *outputParser() const;
-
void emitFaultyConfigurationMessage();
protected:
AbstractProcessStep(BuildStepList *bsl, Core::Id id);
~AbstractProcessStep() override;
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
void doRun() override;
void setLowPriority();
virtual void finish(bool success);
diff --git a/src/plugins/projectexplorer/ansifilterparser.cpp b/src/plugins/projectexplorer/ansifilterparser.cpp
deleted file mode 100644
index a4540845ce..0000000000
--- a/src/plugins/projectexplorer/ansifilterparser.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "ansifilterparser.h"
-
-#ifdef WITH_TESTS
-#include "projectexplorer.h"
-#include "outputparser_test.h"
-#include "task.h"
-
-#include <QTest>
-#endif // WITH_TESTS
-
-
-namespace ProjectExplorer {
-namespace Internal {
-
-enum AnsiState {
- PLAIN,
- ANSI_START,
- ANSI_CSI,
- ANSI_SEQUENCE,
- ANSI_WAITING_FOR_ST,
- ANSI_ST_STARTED
-};
-
-QString filterAnsiEscapeCodes(const QString &line)
-{
- QString result;
- result.reserve(line.count());
-
- static AnsiState state = PLAIN;
- foreach (const QChar c, line) {
- unsigned int val = c.unicode();
- switch (state) {
- case PLAIN:
- if (val == 27) // 'ESC'
- state = ANSI_START;
- else if (val == 155) // equivalent to 'ESC'-'['
- state = ANSI_CSI;
- else
- result.append(c);
- break;
- case ANSI_START:
- if (val == 91) // [
- state = ANSI_CSI;
- else if (val == 80 || val == 93 || val == 94 || val == 95) // 'P', ']', '^' and '_'
- state = ANSI_WAITING_FOR_ST;
- else if (val >= 64 && val <= 95)
- state = PLAIN;
- else
- state = ANSI_SEQUENCE;
- break;
- case ANSI_CSI:
- if (val >= 64 && val <= 126) // Anything between '@' and '~'
- state = PLAIN;
- break;
- case ANSI_SEQUENCE:
- if (val >= 64 && val <= 95) // Anything between '@' and '_'
- state = PLAIN;
- break;
- case ANSI_WAITING_FOR_ST:
- if (val == 7) // 'BEL'
- state = PLAIN;
- if (val == 27) // 'ESC'
- state = ANSI_ST_STARTED;
- break;
- case ANSI_ST_STARTED:
- if (val == 92) // '\'
- state = PLAIN;
- else
- state = ANSI_WAITING_FOR_ST;
- break;
- }
- }
- return result;
-}
-} // namespace Internal
-
-#ifdef WITH_TESTS
-void ProjectExplorerPlugin::testAnsiFilterOutputParser_data()
-{
- QTest::addColumn<QString>("input");
- QTest::addColumn<OutputParserTester::Channel>("inputChannel");
- QTest::addColumn<QString>("childStdOutLines");
- QTest::addColumn<QString>("childStdErrLines");
- QTest::addColumn<QString>("outputLines");
-
- QTest::newRow("pass-through stdout")
- << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
- << QString::fromLatin1("Sometext\n") << QString();
- QTest::newRow("pass-through stderr")
- << QString::fromLatin1("Sometext") << OutputParserTester::STDERR
- << QString() << QString::fromLatin1("Sometext\n");
-
- QString input = QString::fromLatin1("te") + QChar(27) + QString::fromLatin1("Nst");
- QTest::newRow("ANSI: ESC-N")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
- input = QString::fromLatin1("te") + QChar(27) + QLatin1String("^ignored") + QChar(27) + QLatin1String("\\st");
- QTest::newRow("ANSI: ESC-^ignoredESC-\\")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
- input = QString::fromLatin1("te") + QChar(27) + QLatin1String("]0;ignored") + QChar(7) + QLatin1String("st");
- QTest::newRow("ANSI: window title change")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
- input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[Ast");
- QTest::newRow("ANSI: cursor up")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
- input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[2Ast");
- QTest::newRow("ANSI: cursor up (with int parameter)")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
- input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[2;3Hst");
- QTest::newRow("ANSI: position cursor")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
- input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[31;1mst");
- QTest::newRow("ANSI: bold red")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
-}
-
-void ProjectExplorerPlugin::testAnsiFilterOutputParser()
-{
- OutputParserTester testbench;
- testbench.addFilter(&Internal::filterAnsiEscapeCodes);
- QFETCH(QString, input);
- QFETCH(OutputParserTester::Channel, inputChannel);
- QFETCH(QString, childStdOutLines);
- QFETCH(QString, childStdErrLines);
-
- testbench.testParsing(input, inputChannel,
- Tasks(), childStdOutLines, childStdErrLines,
- QString());
-}
-
-#endif
-
-} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/ansifilterparser.h b/src/plugins/projectexplorer/ansifilterparser.h
deleted file mode 100644
index b3ec351c35..0000000000
--- a/src/plugins/projectexplorer/ansifilterparser.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "ioutputparser.h"
-
-#include "projectexplorer_export.h"
-
-namespace ProjectExplorer {
-namespace Internal {
-
-QString filterAnsiEscapeCodes(const QString &line);
-
-} // namespace Internal
-} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/buildmanager.cpp b/src/plugins/projectexplorer/buildmanager.cpp
index 08bfa57de0..e13d12c9d8 100644
--- a/src/plugins/projectexplorer/buildmanager.cpp
+++ b/src/plugins/projectexplorer/buildmanager.cpp
@@ -46,6 +46,7 @@
#include <coreplugin/progressmanager/futureprogress.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <extensionsystem/pluginmanager.h>
+#include <utils/outputformatter.h>
#include <utils/runextensions.h>
#include <utils/stringutils.h>
@@ -680,6 +681,7 @@ void BuildManager::nextStep()
}
static const auto finishedHandler = [](bool success) {
+ d->m_outputWindow->outputFormatter()->flush();
d->m_lastStepSucceeded = success;
disconnect(d->m_currentBuildStep, nullptr, instance(), nullptr);
BuildManager::nextBuildQueue();
@@ -688,6 +690,8 @@ void BuildManager::nextStep()
Qt::QueuedConnection);
connect(d->m_currentBuildStep, &BuildStep::progress,
instance(), &BuildManager::progressChanged);
+ d->m_outputWindow->outputFormatter()->reset();
+ d->m_currentBuildStep->setupOutputFormatter(d->m_outputWindow->outputFormatter());
d->m_currentBuildStep->run();
} else {
d->m_running = false;
diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp
index 319eaf69b6..b7edd0d21a 100644
--- a/src/plugins/projectexplorer/buildstep.cpp
+++ b/src/plugins/projectexplorer/buildstep.cpp
@@ -36,6 +36,8 @@
#include <coreplugin/variablechooser.h>
#include <utils/algorithm.h>
+#include <utils/fileinprojectfinder.h>
+#include <utils/outputformatter.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h>
@@ -254,6 +256,14 @@ QString BuildStep::fallbackWorkingDirectory() const
return {Constants::DEFAULT_WORKING_DIR_ALTERNATE};
}
+void BuildStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ Utils::FileInProjectFinder fileFinder;
+ fileFinder.setProjectDirectory(project()->projectDirectory());
+ fileFinder.setProjectFiles(project()->files(Project::AllFiles));
+ formatter->setFileFinder(fileFinder);
+}
+
void BuildStep::reportRunResult(QFutureInterface<bool> &fi, bool success)
{
fi.reportResult(success);
diff --git a/src/plugins/projectexplorer/buildstep.h b/src/plugins/projectexplorer/buildstep.h
index b8dd6b6718..048b798ba4 100644
--- a/src/plugins/projectexplorer/buildstep.h
+++ b/src/plugins/projectexplorer/buildstep.h
@@ -44,6 +44,7 @@ namespace Utils {
class Environment;
class FilePath;
class MacroExpander;
+class OutputFormatter;
} // Utils
namespace ProjectExplorer {
@@ -91,6 +92,8 @@ public:
Utils::MacroExpander *macroExpander() const;
QString fallbackWorkingDirectory() const;
+ virtual void setupOutputFormatter(Utils::OutputFormatter *formatter);
+
enum class OutputFormat {
Stdout, Stderr, // These are for forwarded output from external tools
NormalMessage, ErrorMessage // These are for messages from Creator itself
@@ -117,8 +120,8 @@ public:
signals:
/// Adds a \p task to the Issues pane.
- /// Do note that for linking compile output with tasks, you should first emit the task
- /// and then emit the output. \p linkedOutput lines will be linked. And the last \p skipLines will
+ /// Do note that for linking compile output with tasks, you should first emit the output
+ /// and then emit the task. \p linkedOutput lines will be linked. And the last \p skipLines will
/// be skipped.
void addTask(const ProjectExplorer::Task &task, int linkedOutputLines = 0, int skipLines = 0);
diff --git a/src/plugins/projectexplorer/clangparser.cpp b/src/plugins/projectexplorer/clangparser.cpp
index 5b6739e544..4df1d5bff7 100644
--- a/src/plugins/projectexplorer/clangparser.cpp
+++ b/src/plugins/projectexplorer/clangparser.cpp
@@ -55,12 +55,12 @@ ClangParser::ClangParser() :
setObjectName(QLatin1String("ClangParser"));
}
-QList<OutputTaskParser *> ClangParser::clangParserSuite()
+QList<OutputLineParser *> ClangParser::clangParserSuite()
{
return {new ClangParser, new Internal::LldParser, new LdParser};
}
-OutputTaskParser::Status ClangParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result ClangParser::handleLine(const QString &line, OutputFormat type)
{
if (type != StdErrFormat)
return Status::NotHandled;
@@ -82,11 +82,12 @@ OutputTaskParser::Status ClangParser::handleLine(const QString &line, OutputForm
match = m_inLineRegExp.match(lne);
if (match.hasMatch()) {
m_expectSnippet = true;
- newTask(CompileTask(Task::Unknown,
- lne.trimmed(),
- absoluteFilePath(FilePath::fromUserInput(match.captured(2))),
- match.captured(3).toInt() /* line */));
- return Status::InProgress;
+ const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(2)));
+ const int lineNo = match.captured(3).toInt();
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 2);
+ newTask(CompileTask(Task::Unknown, lne.trimmed(), filePath, lineNo));
+ return {Status::InProgress, linkSpecs};
}
match = m_messageRegExp.match(lne);
@@ -96,10 +97,10 @@ OutputTaskParser::Status ClangParser::handleLine(const QString &line, OutputForm
int lineNo = match.captured(4).toInt(&ok);
if (!ok)
lineNo = match.captured(5).toInt(&ok);
- newTask(CompileTask(taskType(match.captured(7)),
- match.captured(8),
- absoluteFilePath(FilePath::fromUserInput(match.captured(1))),
- lineNo));
+ const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(1)));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 1);
+ newTask(CompileTask(taskType(match.captured(7)), match.captured(8), filePath, lineNo));
return Status::InProgress;
}
@@ -255,8 +256,7 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
<< (Tasks()
<< CompileTask(Task::Unknown,
"Note: No relevant classes found. No output generated.",
- FilePath::fromUserInput("/home/qtwebkithelpviewer.h"),
- 0))
+ FilePath::fromUserInput("/home/qtwebkithelpviewer.h")))
<< QString();
}
diff --git a/src/plugins/projectexplorer/clangparser.h b/src/plugins/projectexplorer/clangparser.h
index 13b2d9ece6..5b61d0cbaa 100644
--- a/src/plugins/projectexplorer/clangparser.h
+++ b/src/plugins/projectexplorer/clangparser.h
@@ -39,12 +39,12 @@ class PROJECTEXPLORER_EXPORT ClangParser : public ProjectExplorer::GccParser
public:
ClangParser();
- static QList<OutputTaskParser *> clangParserSuite();
+ static QList<Utils::OutputLineParser *> clangParserSuite();
static Core::Id id();
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
QRegularExpression m_commandRegExp;
QRegularExpression m_inLineRegExp;
diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp
index 832318b419..27c0888633 100644
--- a/src/plugins/projectexplorer/compileoutputwindow.cpp
+++ b/src/plugins/projectexplorer/compileoutputwindow.cpp
@@ -24,12 +24,14 @@
****************************************************************************/
#include "compileoutputwindow.h"
+
#include "buildmanager.h"
-#include "showoutputtaskhandler.h"
-#include "task.h"
+#include "ioutputparser.h"
#include "projectexplorer.h"
#include "projectexplorericons.h"
#include "projectexplorersettings.h"
+#include "showoutputtaskhandler.h"
+#include "task.h"
#include "taskhub.h"
#include <coreplugin/outputwindow.h>
@@ -40,7 +42,8 @@
#include <texteditor/texteditorsettings.h>
#include <texteditor/fontsettings.h>
#include <texteditor/behaviorsettings.h>
-#include <utils/outputformat.h>
+#include <utils/algorithm.h>
+#include <utils/outputformatter.h>
#include <utils/proxyaction.h>
#include <utils/theme/theme.h>
#include <utils/utilsicons.h>
@@ -67,74 +70,29 @@ const char WRAP_OUTPUT_KEY[] = "ProjectExplorer/Settings/WrapBuildOutput";
const char MAX_LINES_KEY[] = "ProjectExplorer/Settings/MaxBuildOutputLines";
const char OPTIONS_PAGE_ID[] = "C.ProjectExplorer.CompileOutputOptions";
-class CompileOutputTextEdit : public Core::OutputWindow
-{
- Q_OBJECT
-public:
- CompileOutputTextEdit(const Core::Context &context) : Core::OutputWindow(context, SETTINGS_KEY)
- {
- setMouseTracking(true);
- }
-
- void addTask(const Task &task, int blocknumber)
- {
- m_taskids.insert(blocknumber, task.taskId);
- }
-
- void clearTasks()
- {
- m_taskids.clear();
- }
-
-protected:
- void mouseMoveEvent(QMouseEvent *ev) override
- {
- const int line = cursorForPosition(ev->pos()).block().blockNumber();
- if (m_taskids.contains(line) && m_mousePressButton == Qt::NoButton)
- viewport()->setCursor(Qt::PointingHandCursor);
- else
- viewport()->setCursor(Qt::IBeamCursor);
- QPlainTextEdit::mouseMoveEvent(ev);
- }
-
- void mousePressEvent(QMouseEvent *ev) override
- {
- m_mousePressPosition = ev->pos();
- m_mousePressButton = ev->button();
- QPlainTextEdit::mousePressEvent(ev);
- }
-
- void mouseReleaseEvent(QMouseEvent *ev) override
- {
- if ((m_mousePressPosition - ev->pos()).manhattanLength() < 4
- && m_mousePressButton == Qt::LeftButton) {
- int line = cursorForPosition(ev->pos()).block().blockNumber();
- if (unsigned taskid = m_taskids.value(line, 0))
- TaskHub::showTaskInEditor(taskid);
- }
-
- m_mousePressButton = Qt::NoButton;
- QPlainTextEdit::mouseReleaseEvent(ev);
- }
-
-private:
- QHash<int, unsigned int> m_taskids; //Map blocknumber to taskId
- QPoint m_mousePressPosition;
- Qt::MouseButton m_mousePressButton = Qt::NoButton;
-};
-
CompileOutputWindow::CompileOutputWindow(QAction *cancelBuildAction) :
m_cancelBuildButton(new QToolButton),
m_settingsButton(new QToolButton)
{
Core::Context context(C_COMPILE_OUTPUT);
- m_outputWindow = new CompileOutputTextEdit(context);
+ m_outputWindow = new Core::OutputWindow(context, SETTINGS_KEY);
m_outputWindow->setWindowTitle(displayName());
m_outputWindow->setWindowIcon(Icons::WINDOW.icon());
m_outputWindow->setReadOnly(true);
m_outputWindow->setUndoRedoEnabled(false);
m_outputWindow->setMaxCharCount(Core::Constants::DEFAULT_MAX_CHAR_COUNT);
+ outputFormatter()->overridePostPrintAction([this](Utils::OutputLineParser *parser) {
+ if (const auto taskParser = qobject_cast<OutputTaskParser *>(parser)) {
+ int offset = 0;
+ Utils::reverseForeach(taskParser->taskInfo(), [this, &offset](const OutputTaskParser::TaskInfo &ti) {
+ registerPositionOf(ti.task, ti.linkedLines, ti.skippedLines, offset);
+ offset += ti.linkedLines;
+ });
+ }
+ parser->runPostPrintActions();
+ });
+
// Let selected text be colored as if the text edit was editable,
// otherwise the highlight for searching is too light
QPalette p = m_outputWindow->palette();
@@ -254,7 +212,6 @@ void CompileOutputWindow::appendText(const QString &text, BuildStep::OutputForma
void CompileOutputWindow::clearContents()
{
m_outputWindow->clear();
- m_outputWindow->clearTasks();
m_taskPositions.clear();
}
@@ -287,22 +244,17 @@ bool CompileOutputWindow::canNavigate() const
return false;
}
-void CompileOutputWindow::registerPositionOf(const Task &task, int linkedOutputLines, int skipLines)
+void CompileOutputWindow::registerPositionOf(const Task &task, int linkedOutputLines, int skipLines,
+ int offset)
{
if (linkedOutputLines <= 0)
return;
- const int charNumber = m_outputWindow->document()->characterCount();
- if (charNumber > m_outputWindow->maxCharCount())
- return;
-
- const int blocknumber = m_outputWindow->document()->blockCount();
- const int startLine = blocknumber - linkedOutputLines + 1 - skipLines;
- const int endLine = blocknumber - skipLines;
- m_taskPositions.insert(task.taskId, qMakePair(startLine, endLine));
+ const int blocknumber = m_outputWindow->document()->blockCount() - offset - 1;
+ const int firstLine = blocknumber - linkedOutputLines - skipLines;
+ const int lastLine = firstLine + linkedOutputLines - 1;
- for (int i = startLine; i <= endLine; ++i)
- m_outputWindow->addTask(task, i);
+ m_taskPositions.insert(task.taskId, qMakePair(firstLine, lastLine));
}
bool CompileOutputWindow::knowsPositionOf(const Task &task)
@@ -340,6 +292,11 @@ void CompileOutputWindow::setSettings(const CompileOutputSettings &settings)
updateFromSettings();
}
+Utils::OutputFormatter *CompileOutputWindow::outputFormatter() const
+{
+ return m_outputWindow->outputFormatter();
+}
+
void CompileOutputWindow::updateFilter()
{
m_outputWindow->updateFilterProperties(filterText(), filterCaseSensitivity(),
@@ -415,5 +372,3 @@ CompileOutputSettingsPage::CompileOutputSettingsPage()
} // Internal
} // ProjectExplorer
-
-#include "compileoutputwindow.moc"
diff --git a/src/plugins/projectexplorer/compileoutputwindow.h b/src/plugins/projectexplorer/compileoutputwindow.h
index adea3aca80..caed6e8d66 100644
--- a/src/plugins/projectexplorer/compileoutputwindow.h
+++ b/src/plugins/projectexplorer/compileoutputwindow.h
@@ -37,6 +37,9 @@ QT_BEGIN_NAMESPACE
class QToolButton;
QT_END_NAMESPACE
+namespace Core { class OutputWindow; }
+namespace Utils { class OutputFormatter; }
+
namespace ProjectExplorer {
class Task;
@@ -70,7 +73,7 @@ public:
void appendText(const QString &text, BuildStep::OutputFormat format);
- void registerPositionOf(const Task &task, int linkedOutputLines, int skipLines);
+ void registerPositionOf(const Task &task, int linkedOutputLines, int skipLines, int offset = 0);
bool knowsPositionOf(const Task &task);
void showPositionOf(const Task &task);
@@ -79,6 +82,8 @@ public:
const CompileOutputSettings &settings() const { return m_settings; }
void setSettings(const CompileOutputSettings &settings);
+ Utils::OutputFormatter *outputFormatter() const;
+
private:
void updateFilter() override;
@@ -86,7 +91,7 @@ private:
void storeSettings() const;
void updateFromSettings();
- CompileOutputTextEdit *m_outputWindow;
+ Core::OutputWindow *m_outputWindow;
QHash<unsigned int, QPair<int, int>> m_taskPositions;
ShowOutputTaskHandler *m_handler;
QToolButton *m_cancelBuildButton;
diff --git a/src/plugins/projectexplorer/customparser.cpp b/src/plugins/projectexplorer/customparser.cpp
index cff4893f76..dfd588fe20 100644
--- a/src/plugins/projectexplorer/customparser.cpp
+++ b/src/plugins/projectexplorer/customparser.cpp
@@ -129,45 +129,51 @@ Core::Id CustomParser::id()
return Core::Id("ProjectExplorer.OutputParser.Custom");
}
-OutputTaskParser::Status CustomParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result CustomParser::handleLine(const QString &line, OutputFormat type)
{
const CustomParserExpression::CustomParserChannel channel = type == StdErrFormat
? CustomParserExpression::ParseStdErrChannel
: CustomParserExpression::ParseStdOutChannel;
- if (parseLine(line, channel))
- return Status::Done;
- return Status::NotHandled;
+ return parseLine(line, channel);
}
-bool CustomParser::hasMatch(const QString &line, CustomParserExpression::CustomParserChannel channel,
- const CustomParserExpression &expression, Task::TaskType taskType)
+OutputLineParser::Result CustomParser::hasMatch(
+ const QString &line,
+ CustomParserExpression::CustomParserChannel channel,
+ const CustomParserExpression &expression,
+ Task::TaskType taskType
+ )
{
if (!(channel & expression.channel()))
- return false;
+ return Status::NotHandled;
if (expression.pattern().isEmpty())
- return false;
+ return Status::NotHandled;
const QRegularExpressionMatch match = expression.match(line);
if (!match.hasMatch())
- return false;
+ return Status::NotHandled;
const FilePath fileName = absoluteFilePath(FilePath::fromString(
match.captured(expression.fileNameCap())));
const int lineNumber = match.captured(expression.lineNumberCap()).toInt();
const QString message = match.captured(expression.messageCap());
-
- emit addTask(CompileTask(taskType, message, fileName, lineNumber), 1);
- return true;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, fileName, lineNumber, match,
+ expression.fileNameCap());
+ scheduleTask(CompileTask(taskType, message, fileName, lineNumber), 1);
+ return Status::Done;
}
-bool CustomParser::parseLine(const QString &rawLine, CustomParserExpression::CustomParserChannel channel)
+OutputLineParser::Result CustomParser::parseLine(
+ const QString &rawLine,
+ CustomParserExpression::CustomParserChannel channel
+ )
{
const QString line = rawLine.trimmed();
-
- if (hasMatch(line, channel, m_error, Task::Error))
- return true;
-
+ const Result res = hasMatch(line, channel, m_error, Task::Error);
+ if (res.status != Status::NotHandled)
+ return res;
return hasMatch(line, channel, m_warning, Task::Warning);
}
diff --git a/src/plugins/projectexplorer/customparser.h b/src/plugins/projectexplorer/customparser.h
index a7e7d15d7f..00069f117f 100644
--- a/src/plugins/projectexplorer/customparser.h
+++ b/src/plugins/projectexplorer/customparser.h
@@ -91,11 +91,11 @@ public:
static Core::Id id();
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
- bool hasMatch(const QString &line, CustomParserExpression::CustomParserChannel channel,
- const CustomParserExpression &expression, Task::TaskType taskType);
- bool parseLine(const QString &rawLine, CustomParserExpression::CustomParserChannel channel);
+ Result hasMatch(const QString &line, CustomParserExpression::CustomParserChannel channel,
+ const CustomParserExpression &expression, Task::TaskType taskType);
+ Result parseLine(const QString &rawLine, CustomParserExpression::CustomParserChannel channel);
CustomParserExpression m_error;
CustomParserExpression m_warning;
diff --git a/src/plugins/projectexplorer/customtoolchain.cpp b/src/plugins/projectexplorer/customtoolchain.cpp
index 8c95e58921..abe682a48e 100644
--- a/src/plugins/projectexplorer/customtoolchain.cpp
+++ b/src/plugins/projectexplorer/customtoolchain.cpp
@@ -196,7 +196,7 @@ QStringList CustomToolChain::suggestedMkspecList() const
return m_mkspecs;
}
-QList<OutputTaskParser *> CustomToolChain::createOutputParsers() const
+QList<Utils::OutputLineParser *> CustomToolChain::createOutputParsers() const
{
if (m_outputParserId == GccParser::id())
return GccParser::gccParserSuite();
diff --git a/src/plugins/projectexplorer/customtoolchain.h b/src/plugins/projectexplorer/customtoolchain.h
index 8274241695..dc57fe3503 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;
- QList<OutputTaskParser *> createOutputParsers() const override;
+ QList<Utils::OutputLineParser *> createOutputParsers() 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 a0bcf92fd6..2e55e9178f 100644
--- a/src/plugins/projectexplorer/gccparser.cpp
+++ b/src/plugins/projectexplorer/gccparser.cpp
@@ -66,7 +66,7 @@ Core::Id GccParser::id()
return Core::Id("ProjectExplorer.OutputParser.Gcc");
}
-QList<OutputTaskParser *> GccParser::gccParserSuite()
+QList<OutputLineParser *> GccParser::gccParserSuite()
{
return {new GccParser, new Internal::LldParser, new LdParser};
}
@@ -84,7 +84,7 @@ void GccParser::flush()
return;
Task t = m_currentTask;
m_currentTask.clear();
- emit addTask(t, m_lines, 1);
+ scheduleTask(t, m_lines, 1);
m_lines = 0;
}
@@ -107,11 +107,9 @@ void GccParser::amendDescription(const QString &desc, bool monospaced)
return;
}
-OutputTaskParser::Status GccParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result GccParser::handleLine(const QString &line, OutputFormat type)
{
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
flush();
return Status::NotHandled;
}
@@ -146,7 +144,6 @@ OutputTaskParser::Status GccParser::handleLine(const QString &line, OutputFormat
match = m_regExp.match(lne);
if (match.hasMatch()) {
- Utils::FilePath filename = Utils::FilePath::fromUserInput(match.captured(1));
int lineno = match.captured(3).toInt();
Task::TaskType type = Task::Unknown;
QString description = match.captured(8);
@@ -161,17 +158,21 @@ OutputTaskParser::Status GccParser::handleLine(const QString &line, OutputFormat
if (match.captured(5).startsWith(QLatin1Char('#')))
description = match.captured(5) + description;
- newTask(CompileTask(type, description, absoluteFilePath(filename), lineno));
- return Status::InProgress;
+ const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(1)));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineno, match, 1);
+ newTask(CompileTask(type, description, filePath, lineno));
+ return {Status::InProgress, linkSpecs};
}
match = m_regExpIncluded.match(lne);
if (match.hasMatch()) {
- newTask(CompileTask(Task::Unknown,
- lne.trimmed() /* description */,
- absoluteFilePath(Utils::FilePath::fromUserInput(match.captured(1))),
- match.captured(3).toInt() /* linenumber */));
- return Status::InProgress;
+ const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(1)));
+ const int lineNo = match.captured(3).toInt();
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 1);
+ newTask(CompileTask(Task::Unknown, lne.trimmed() /* description */, filePath, lineNo));
+ return {Status::InProgress, linkSpecs};
} else if (lne.startsWith(' ') && !m_currentTask.isNull()) {
amendDescription(lne, true);
return Status::InProgress;
@@ -681,8 +682,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< (Tasks()
<< CompileTask(Task::Unknown,
"In file included from <command-line>:0:0:",
- FilePath::fromUserInput("<command-line>"),
- 0)
+ FilePath::fromUserInput("<command-line>"))
<< CompileTask(Task::Warning,
"\"STUPID_DEFINE\" redefined",
FilePath::fromUserInput("./mw.h"),
@@ -1009,8 +1009,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< (Tasks()
<< CompileTask(Task::Unknown,
"Note: No relevant classes found. No output generated.",
- FilePath::fromUserInput("/home/qtwebkithelpviewer.h"),
- 0))
+ FilePath::fromUserInput("/home/qtwebkithelpviewer.h")))
<< QString();
QTest::newRow("GCC 9 output")
diff --git a/src/plugins/projectexplorer/gccparser.h b/src/plugins/projectexplorer/gccparser.h
index 46b4de42d1..76afb53668 100644
--- a/src/plugins/projectexplorer/gccparser.h
+++ b/src/plugins/projectexplorer/gccparser.h
@@ -42,7 +42,7 @@ public:
static Core::Id id();
- static QList<OutputTaskParser *> gccParserSuite();
+ static QList<OutputLineParser *> gccParserSuite();
protected:
void newTask(const Task &task);
@@ -51,7 +51,7 @@ protected:
void amendDescription(const QString &desc, bool monospaced);
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(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 22054d6828..81a0b015b0 100644
--- a/src/plugins/projectexplorer/gcctoolchain.cpp
+++ b/src/plugins/projectexplorer/gcctoolchain.cpp
@@ -731,7 +731,7 @@ FilePath GccToolChain::makeCommand(const Environment &environment) const
return tmp.isEmpty() ? FilePath::fromString("make") : tmp;
}
-QList<OutputTaskParser *> GccToolChain::createOutputParsers() const
+QList<OutputLineParser *> GccToolChain::createOutputParsers() const
{
return GccParser::gccParserSuite();
}
@@ -1628,7 +1628,7 @@ LanguageExtensions ClangToolChain::defaultLanguageExtensions() const
return LanguageExtension::Gnu;
}
-QList<OutputTaskParser *> ClangToolChain::createOutputParsers() const
+QList<OutputLineParser *> ClangToolChain::createOutputParsers() const
{
return ClangParser::clangParserSuite();
}
@@ -1898,7 +1898,7 @@ LanguageExtensions LinuxIccToolChain::languageExtensions(const QStringList &cxxf
return extensions;
}
-QList<OutputTaskParser *> LinuxIccToolChain::createOutputParsers() const
+QList<OutputLineParser *> LinuxIccToolChain::createOutputParsers() const
{
return LinuxIccParser::iccParserSuite();
}
diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h
index 4e22ba05ef..72c693ea2c 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;
- QList<OutputTaskParser *> createOutputParsers() const override;
+ QList<Utils::OutputLineParser *> createOutputParsers() 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;
- QList<OutputTaskParser *> createOutputParsers() const override;
+ QList<Utils::OutputLineParser *> createOutputParsers() 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;
- QList<OutputTaskParser *> createOutputParsers() const override;
+ QList<Utils::OutputLineParser *> createOutputParsers() const override;
QStringList suggestedMkspecList() const override;
diff --git a/src/plugins/projectexplorer/gnumakeparser.cpp b/src/plugins/projectexplorer/gnumakeparser.cpp
index 53d0db07a8..6bb7442e0c 100644
--- a/src/plugins/projectexplorer/gnumakeparser.cpp
+++ b/src/plugins/projectexplorer/gnumakeparser.cpp
@@ -100,10 +100,10 @@ void GnuMakeParser::emitTask(const ProjectExplorer::Task &task)
{
if (task.type == Task::Error) // Assume that all make errors will be follow up errors.
m_suppressIssues = true;
- emit addTask(task, 1, 0);
+ scheduleTask(task, 1, 0);
}
-OutputTaskParser::Status GnuMakeParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result GnuMakeParser::handleLine(const QString &line, OutputFormat type)
{
const QString lne = rightTrimmed(line);
if (type == StdOutFormat) {
@@ -119,19 +119,21 @@ OutputTaskParser::Status GnuMakeParser::handleLine(const QString &line, OutputFo
}
QRegularExpressionMatch match = m_errorInMakefile.match(lne);
if (match.hasMatch()) {
- Result res = parseDescription(match.captured(5));
+ ProjectExplorer::Result res = parseDescription(match.captured(5));
if (res.isFatal)
++m_fatalErrorCount;
+ LinkSpecs linkSpecs;
if (!m_suppressIssues) {
- emitTask(BuildSystemTask(res.type, res.description,
- absoluteFilePath(FilePath::fromUserInput(match.captured(1))),
- match.captured(4).toInt() /* line */));
+ const FilePath file = absoluteFilePath(FilePath::fromUserInput(match.captured(1)));
+ const int lineNo = match.captured(4).toInt();
+ addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineNo, match, 1);
+ emitTask(BuildSystemTask(res.type, res.description, file, lineNo));
}
- return Status::Done;
+ return {Status::Done, linkSpecs};
}
match = m_makeLine.match(lne);
if (match.hasMatch()) {
- Result res = parseDescription(match.captured(6));
+ ProjectExplorer::Result res = parseDescription(match.captured(6));
if (res.isFatal)
++m_fatalErrorCount;
if (!m_suppressIssues)
diff --git a/src/plugins/projectexplorer/gnumakeparser.h b/src/plugins/projectexplorer/gnumakeparser.h
index 5a2f247a4f..21c77213b1 100644
--- a/src/plugins/projectexplorer/gnumakeparser.h
+++ b/src/plugins/projectexplorer/gnumakeparser.h
@@ -40,7 +40,7 @@ public:
explicit GnuMakeParser();
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
bool hasFatalErrors() const override;
void emitTask(const ProjectExplorer::Task &task);
diff --git a/src/plugins/projectexplorer/ioutputparser.cpp b/src/plugins/projectexplorer/ioutputparser.cpp
index 98f39fb4db..72d4e28fe1 100644
--- a/src/plugins/projectexplorer/ioutputparser.cpp
+++ b/src/plugins/projectexplorer/ioutputparser.cpp
@@ -24,15 +24,9 @@
****************************************************************************/
#include "ioutputparser.h"
-#include "task.h"
-
-#include <utils/algorithm.h>
-#include <utils/fileinprojectfinder.h>
-#include <utils/synchronousprocess.h>
-#include <QDir>
-#include <QFileInfo>
-#include <QPointer>
+#include "task.h"
+#include "taskhub.h"
/*!
@@ -76,296 +70,32 @@ namespace ProjectExplorer {
class OutputTaskParser::Private
{
public:
- Utils::FilePaths searchDirs;
- Utils::FileInProjectFinder *fileFinder = nullptr;
- QPointer<const OutputTaskParser> redirectionDetector;
- bool skipFileExistsCheck = false;
+ QList<TaskInfo> scheduledTasks;
};
-OutputTaskParser::OutputTaskParser() : d(new Private)
-{
-}
+OutputTaskParser::OutputTaskParser() : d(new Private) { }
OutputTaskParser::~OutputTaskParser() { delete d; }
-void OutputTaskParser::addSearchDir(const Utils::FilePath &dir)
-{
- d->searchDirs << dir;
-}
-
-void OutputTaskParser::dropSearchDir(const Utils::FilePath &dir)
-{
- const int idx = d->searchDirs.lastIndexOf(dir);
-
- // TODO: This apparently triggers. Find out why and either remove the assertion (if it's legit)
- // or fix the culprit.
- QTC_ASSERT(idx != -1, return);
-
- d->searchDirs.removeAt(idx);
-}
-
-const Utils::FilePaths OutputTaskParser::searchDirectories() const
-{
- return d->searchDirs;
-}
-
-// 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 OutputTaskParser::setRedirectionDetector(const OutputTaskParser *detector)
-{
- d->redirectionDetector = detector;
-}
-
-bool OutputTaskParser::needsRedirection() const
-{
- return d->redirectionDetector && (d->redirectionDetector->hasDetectedRedirection()
- || d->redirectionDetector->needsRedirection());
-}
-
-void OutputTaskParser::setFileFinder(Utils::FileInProjectFinder *finder)
-{
- d->fileFinder = finder;
-}
-
-Utils::FilePath OutputTaskParser::absoluteFilePath(const Utils::FilePath &filePath)
-{
- if (filePath.isEmpty() || filePath.toFileInfo().isAbsolute())
- return filePath;
- Utils::FilePaths candidates;
- for (const Utils::FilePath &dir : searchDirectories()) {
- const Utils::FilePath candidate = dir.pathAppended(filePath.toString());
- if (candidate.exists() || d->skipFileExistsCheck)
- candidates << candidate;
- }
- if (candidates.count() == 1)
- return Utils::FilePath::fromString(QDir::cleanPath(candidates.first().toString()));
-
- QString fp = filePath.toString();
- while (fp.startsWith("../"))
- fp.remove(0, 3);
- bool found = false;
- candidates = d->fileFinder->findFile(QUrl::fromLocalFile(fp), &found);
- if (found && candidates.size() == 1)
- return candidates.first();
-
- return filePath;
-}
-
-QString OutputTaskParser::rightTrimmed(const QString &in)
-{
- int pos = in.length();
- for (; pos > 0; --pos) {
- if (!in.at(pos - 1).isSpace())
- break;
- }
- return in.mid(0, pos);
-}
-
-#ifdef WITH_TESTS
-void OutputTaskParser::skipFileExistsCheck()
-{
- d->skipFileExistsCheck = true;
-}
-#endif
-
-class IOutputParser::OutputChannelState
-{
-public:
- using LineHandler = void (IOutputParser::*)(const QString &line);
-
- OutputChannelState(IOutputParser *parser, Utils::OutputFormat type)
- : parser(parser), type(type) {}
-
- void handleData(const QString &newData)
- {
- pendingData += newData;
- pendingData = Utils::SynchronousProcess::normalizeNewlines(pendingData);
- while (true) {
- const int eolPos = pendingData.indexOf('\n');
- if (eolPos == -1)
- break;
- const QString line = pendingData.left(eolPos + 1);
- pendingData.remove(0, eolPos + 1);
- parser->handleLine(line, type);
- }
- }
-
- void flush()
- {
- if (!pendingData.isEmpty()) {
- parser->handleLine(pendingData, type);
- pendingData.clear();
- }
- }
-
- IOutputParser * const parser;
- const Utils::OutputFormat type;
- QString pendingData;
-};
-
-class IOutputParser::IOutputParserPrivate
-{
-public:
- IOutputParserPrivate(IOutputParser *parser)
- : stdoutState(parser, Utils::StdOutFormat),
- stderrState(parser, Utils::StdErrFormat)
- {}
-
- QList<OutputTaskParser *> lineParsers;
- OutputTaskParser *nextParser = nullptr;
- QList<Filter> filters;
- Utils::FileInProjectFinder fileFinder;
- OutputChannelState stdoutState;
- OutputChannelState stderrState;
-};
-
-IOutputParser::IOutputParser() : d(new IOutputParserPrivate(this))
-{
-}
-
-IOutputParser::~IOutputParser()
-{
- clear();
- delete d;
-}
-
-void IOutputParser::handleStdout(const QString &data)
-{
- d->stdoutState.handleData(data);
-}
-
-void IOutputParser::handleStderr(const QString &data)
-{
- d->stderrState.handleData(data);
-}
-
-void IOutputParser::handleLine(const QString &line, Utils::OutputFormat type)
-{
- const QString cleanLine = filteredLine(line);
- if (d->nextParser) {
- switch (d->nextParser->handleLine(cleanLine, outputTypeForParser(d->nextParser, type))) {
- case OutputTaskParser::Status::Done:
- d->nextParser = nullptr;
- return;
- case OutputTaskParser::Status::InProgress:
- return;
- case OutputTaskParser::Status::NotHandled:
- d->nextParser = nullptr;
- break;
- }
- }
- QTC_CHECK(!d->nextParser);
- for (OutputTaskParser * const lineParser : d->lineParsers) {
- switch (lineParser->handleLine(cleanLine, outputTypeForParser(lineParser, type))) {
- case OutputTaskParser::Status::Done:
- return;
- case OutputTaskParser::Status::InProgress:
- d->nextParser = lineParser;
- return;
- case OutputTaskParser::Status::NotHandled:
- break;
- }
- }
-}
-
-QString IOutputParser::filteredLine(const QString &line) const
-{
- QString l = line;
- for (const IOutputParser::Filter &f : qAsConst(d->filters))
- l = f(l);
- return l;
-}
-
-void IOutputParser::setupLineParser(OutputTaskParser *parser)
-{
- parser->setFileFinder(&d->fileFinder);
- connect(parser, &OutputTaskParser::addTask, this, &IOutputParser::addTask);
- connect(parser, &OutputTaskParser::newSearchDir, this, &IOutputParser::addSearchDir);
- connect(parser, &OutputTaskParser::searchDirExpired, this, &IOutputParser::dropSearchDir);
-}
-
-bool IOutputParser::hasFatalErrors() const
-{
- return Utils::anyOf(d->lineParsers, [](const OutputTaskParser *p) {
- return p->hasFatalErrors();
- });
-}
-
-void IOutputParser::flush()
-{
- d->stdoutState.flush();
- d->stderrState.flush();
- for (OutputTaskParser * const p : qAsConst(d->lineParsers))
- p->flush();
-}
-
-void IOutputParser::clear()
-{
- d->nextParser = nullptr;
- d->filters.clear();
- qDeleteAll(d->lineParsers);
- d->lineParsers.clear();
- d->stdoutState.pendingData.clear();
- d->stderrState.pendingData.clear();
- d->fileFinder = Utils::FileInProjectFinder();
-}
-
-void IOutputParser::addLineParser(OutputTaskParser *parser)
-{
- setupLineParser(parser);
- d->lineParsers << parser;
-}
-
-void IOutputParser::addLineParsers(const QList<OutputTaskParser *> &parsers)
-{
- for (OutputTaskParser * const p : qAsConst(parsers))
- addLineParser(p);
-}
-
-void IOutputParser::setLineParsers(const QList<OutputTaskParser *> &parsers)
-{
- qDeleteAll(d->lineParsers);
- d->lineParsers.clear();
- addLineParsers(parsers);
-}
-
-void IOutputParser::setFileFinder(const Utils::FileInProjectFinder &finder)
-{
- d->fileFinder = finder;
-}
-
-#ifdef WITH_TESTS
-QList<OutputTaskParser *> IOutputParser::lineParsers() const
-{
- return d->lineParsers;
-}
-#endif // WITH_TESTS
-
-void IOutputParser::addFilter(const Filter &filter)
-{
- d->filters << filter;
-}
-
-void IOutputParser::addSearchDir(const Utils::FilePath &dir)
+const QList<OutputTaskParser::TaskInfo> OutputTaskParser::taskInfo() const
{
- for (OutputTaskParser * const p : qAsConst(d->lineParsers))
- p->addSearchDir(dir);
+ return d->scheduledTasks;
}
-void IOutputParser::dropSearchDir(const Utils::FilePath &dir)
+void OutputTaskParser::scheduleTask(const Task &task, int outputLines, int skippedLines)
{
- for (OutputTaskParser * const p : qAsConst(d->lineParsers))
- p->dropSearchDir(dir);
+ TaskInfo ts(task, outputLines, skippedLines);
+ if (ts.task.type == Task::Error && demoteErrorsToWarnings())
+ ts.task.type = Task::Warning;
+ d->scheduledTasks << ts;
+ QTC_CHECK(d->scheduledTasks.size() <= 2);
}
-Utils::OutputFormat IOutputParser::outputTypeForParser(const OutputTaskParser *parser,
- Utils::OutputFormat type) const
+void OutputTaskParser::runPostPrintActions()
{
- if (type == Utils::StdOutFormat && parser->needsRedirection())
- return Utils::StdErrFormat;
- return type;
+ for (const TaskInfo &t : qAsConst(d->scheduledTasks))
+ TaskHub::addTask(t.task);
+ d->scheduledTasks.clear();
}
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/ioutputparser.h b/src/plugins/projectexplorer/ioutputparser.h
index efe717f1f0..9a8ce59be1 100644
--- a/src/plugins/projectexplorer/ioutputparser.h
+++ b/src/plugins/projectexplorer/ioutputparser.h
@@ -28,103 +28,38 @@
#include "projectexplorer_export.h"
#include "buildstep.h"
-#include <utils/fileutils.h>
-#include <utils/outputformat.h>
+#include <utils/outputformatter.h>
#include <functional>
-namespace Utils { class FileInProjectFinder; }
-
namespace ProjectExplorer {
class Task;
-class PROJECTEXPLORER_EXPORT OutputTaskParser : public QObject
+class PROJECTEXPLORER_EXPORT OutputTaskParser : public Utils::OutputLineParser
{
Q_OBJECT
public:
OutputTaskParser();
~OutputTaskParser() override;
- void addSearchDir(const Utils::FilePath &dir);
- void dropSearchDir(const Utils::FilePath &dir);
- const Utils::FilePaths searchDirectories() const;
-
- enum class Status { Done, InProgress, NotHandled };
- virtual Status handleLine(const QString &line, Utils::OutputFormat type) = 0;
-
- virtual bool hasFatalErrors() const { return false; }
- virtual void flush() {}
-
- void setRedirectionDetector(const OutputTaskParser *detector);
- bool needsRedirection() const;
- virtual bool hasDetectedRedirection() const { return false; }
-
- void setFileFinder(Utils::FileInProjectFinder *finder);
-
-#ifdef WITH_TESTS
- void skipFileExistsCheck();
-#endif
-
-signals:
- void newSearchDir(const Utils::FilePath &dir);
- void searchDirExpired(const Utils::FilePath &dir);
- void addTask(const ProjectExplorer::Task &task, int linkedOutputLines = 0, int skipLines = 0);
+ class TaskInfo
+ {
+ public:
+ TaskInfo(const Task &t, int l, int s) : task(t), linkedLines(l), skippedLines(s) {}
+ Task task;
+ int linkedLines = 0;
+ int skippedLines = 0;
+ };
+ const QList<TaskInfo> taskInfo() const;
protected:
- static QString rightTrimmed(const QString &in);
- Utils::FilePath absoluteFilePath(const Utils::FilePath &filePath);
+ void scheduleTask(const Task &task, int outputLines, int skippedLines = 0);
private:
+ void runPostPrintActions() override;
+
class Private;
Private * const d;
};
-// Documentation inside.
-class PROJECTEXPLORER_EXPORT IOutputParser : public QObject
-{
- Q_OBJECT
-public:
- IOutputParser();
- ~IOutputParser() override;
-
- void handleStdout(const QString &data);
- void handleStderr(const QString &data);
-
- bool hasFatalErrors() const;
-
- using Filter = std::function<QString(const QString &)>;
- void addFilter(const Filter &filter);
-
- // Forwards to line parsers. Add those before.
- void addSearchDir(const Utils::FilePath &dir);
- void dropSearchDir(const Utils::FilePath &dir);
-
- void flush();
- void clear();
-
- void addLineParser(OutputTaskParser *parser);
- void addLineParsers(const QList<OutputTaskParser *> &parsers);
- void setLineParsers(const QList<OutputTaskParser *> &parsers);
-
- void setFileFinder(const Utils::FileInProjectFinder &finder);
-
-#ifdef WITH_TESTS
- QList<OutputTaskParser *> lineParsers() const;
-#endif
-
-signals:
- void addTask(const ProjectExplorer::Task &task, int linkedOutputLines = 0, int skipLines = 0);
-
-private:
- void handleLine(const QString &line, Utils::OutputFormat type);
- QString filteredLine(const QString &line) const;
- void setupLineParser(OutputTaskParser *parser);
- Utils::OutputFormat outputTypeForParser(const OutputTaskParser *parser,
- Utils::OutputFormat type) const;
-
- class OutputChannelState;
- class IOutputParserPrivate;
- IOutputParserPrivate * const d;
-};
-
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/kit.cpp b/src/plugins/projectexplorer/kit.cpp
index 0cd845e5d3..e8ff3cab48 100644
--- a/src/plugins/projectexplorer/kit.cpp
+++ b/src/plugins/projectexplorer/kit.cpp
@@ -559,9 +559,9 @@ void Kit::addToEnvironment(Environment &env) const
aspect->addToEnvironment(this, env);
}
-QList<OutputTaskParser *> Kit::createOutputParsers() const
+QList<OutputLineParser *> Kit::createOutputParsers() const
{
- QList<OutputTaskParser *> parsers{new OsParser};
+ QList<OutputLineParser *> parsers{new OsParser};
for (KitAspect *aspect : KitManager::kitAspects())
parsers << aspect->createOutputParsers(this);
return parsers;
diff --git a/src/plugins/projectexplorer/kit.h b/src/plugins/projectexplorer/kit.h
index 8408eab788..871e226568 100644
--- a/src/plugins/projectexplorer/kit.h
+++ b/src/plugins/projectexplorer/kit.h
@@ -38,10 +38,10 @@
namespace Utils {
class Environment;
class MacroExpander;
+class OutputLineParser;
} // namespace Utils
namespace ProjectExplorer {
-class OutputTaskParser;
namespace Internal {
class KitManagerPrivate;
@@ -116,7 +116,7 @@ public:
bool isEqual(const Kit *other) const;
void addToEnvironment(Utils::Environment &env) const;
- QList<OutputTaskParser *> createOutputParsers() const;
+ QList<Utils::OutputLineParser *> 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 590a777b14..9d67eed17a 100644
--- a/src/plugins/projectexplorer/kitinformation.cpp
+++ b/src/plugins/projectexplorer/kitinformation.cpp
@@ -557,7 +557,7 @@ void ToolChainKitAspect::addToMacroExpander(Kit *kit, Utils::MacroExpander *expa
});
}
-QList<OutputTaskParser *> ToolChainKitAspect::createOutputParsers(const Kit *k) const
+QList<Utils::OutputLineParser *> 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))
diff --git a/src/plugins/projectexplorer/kitinformation.h b/src/plugins/projectexplorer/kitinformation.h
index 6b5c77dc97..d8558b8861 100644
--- a/src/plugins/projectexplorer/kitinformation.h
+++ b/src/plugins/projectexplorer/kitinformation.h
@@ -85,7 +85,7 @@ public:
void addToEnvironment(const Kit *k, Utils::Environment &env) const override;
void addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const override;
- QList<OutputTaskParser *> createOutputParsers(const Kit *k) const override;
+ QList<Utils::OutputLineParser *> 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 5d82fe6e28..1eab4633f5 100644
--- a/src/plugins/projectexplorer/kitmanager.cpp
+++ b/src/plugins/projectexplorer/kitmanager.cpp
@@ -677,7 +677,7 @@ void KitAspect::addToEnvironment(const Kit *k, Environment &env) const
Q_UNUSED(env)
}
-QList<OutputTaskParser *> KitAspect::createOutputParsers(const Kit *k) const
+QList<OutputLineParser *> KitAspect::createOutputParsers(const Kit *k) const
{
Q_UNUSED(k)
return {};
diff --git a/src/plugins/projectexplorer/kitmanager.h b/src/plugins/projectexplorer/kitmanager.h
index 31565eec5c..f55380c573 100644
--- a/src/plugins/projectexplorer/kitmanager.h
+++ b/src/plugins/projectexplorer/kitmanager.h
@@ -42,11 +42,11 @@ namespace Utils {
class Environment;
class FilePath;
class MacroExpander;
+class OutputLineParser;
} // namespace Utils
namespace ProjectExplorer {
class Task;
-class OutputTaskParser;
class KitAspectWidget;
class KitManager;
@@ -91,7 +91,7 @@ public:
virtual KitAspectWidget *createConfigWidget(Kit *) const = 0;
virtual void addToEnvironment(const Kit *k, Utils::Environment &env) const;
- virtual QList<OutputTaskParser *> createOutputParsers(const Kit *k) const;
+ virtual QList<Utils::OutputLineParser *> 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 55ef296bf8..135401dd1c 100644
--- a/src/plugins/projectexplorer/ldparser.cpp
+++ b/src/plugins/projectexplorer/ldparser.cpp
@@ -54,7 +54,7 @@ LdParser::LdParser()
QTC_CHECK(m_regExpGccNames.isValid());
}
-OutputTaskParser::Status LdParser::handleLine(const QString &line, Utils::OutputFormat type)
+Utils::OutputLineParser::Result LdParser::handleLine(const QString &line, Utils::OutputFormat type)
{
if (type != Utils::StdErrFormat)
return Status::NotHandled;
@@ -80,20 +80,24 @@ OutputTaskParser::Status LdParser::handleLine(const QString &line, Utils::Output
m_incompleteTask.description.append('\n').append(lne);
static const QRegularExpression locRegExp(" (?<symbol>\\S+) in (?<file>\\S+)");
const QRegularExpressionMatch match = locRegExp.match(lne);
- if (match.hasMatch())
- m_incompleteTask.setFile(Utils::FilePath::fromString(match.captured("file")));
- return Status::InProgress;
+ LinkSpecs linkSpecs;
+ if (match.hasMatch()) {
+ m_incompleteTask.setFile(absoluteFilePath(Utils::FilePath::fromString(
+ match.captured("file"))));
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_incompleteTask.file, 0, match, "file");
+ }
+ return {Status::InProgress, linkSpecs};
}
if (lne.startsWith("collect2:") || lne.startsWith("collect2.exe:")) {
- emit addTask(CompileTask(Task::Error, lne /* description */), 1);
+ scheduleTask(CompileTask(Task::Error, lne /* description */), 1);
return Status::Done;
}
QRegularExpressionMatch match = m_ranlib.match(lne);
if (match.hasMatch()) {
QString description = match.captured(2);
- emit addTask(CompileTask(Task::Warning, description), 1);
+ scheduleTask(CompileTask(Task::Warning, description), 1);
return Status::Done;
}
@@ -107,7 +111,7 @@ OutputTaskParser::Status LdParser::handleLine(const QString &line, Utils::Output
} else if (description.startsWith(QLatin1String("fatal: "))) {
description = description.mid(7);
}
- emit addTask(CompileTask(type, description), 1);
+ scheduleTask(CompileTask(type, description), 1);
return Status::Done;
}
@@ -117,12 +121,15 @@ OutputTaskParser::Status LdParser::handleLine(const QString &line, Utils::Output
int lineno = match.captured(7).toInt(&ok);
if (!ok)
lineno = -1;
- Utils::FilePath filename = Utils::FilePath::fromUserInput(match.captured(1));
+ Utils::FilePath filename
+ = absoluteFilePath(Utils::FilePath::fromUserInput(match.captured(1)));
+ int capIndex = 1;
const QString sourceFileName = match.captured(4);
if (!sourceFileName.isEmpty()
&& !sourceFileName.startsWith(QLatin1String("(.text"))
&& !sourceFileName.startsWith(QLatin1String("(.data"))) {
- filename = Utils::FilePath::fromUserInput(sourceFileName);
+ filename = absoluteFilePath(Utils::FilePath::fromUserInput(sourceFileName));
+ capIndex = 4;
}
QString description = match.captured(8).trimmed();
Task::TaskType type = Task::Error;
@@ -137,8 +144,10 @@ OutputTaskParser::Status LdParser::handleLine(const QString &line, Utils::Output
type = Task::Warning;
description = description.mid(9);
}
- emit addTask(CompileTask(type, description, absoluteFilePath(filename), lineno), 1);
- return Status::Done;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filename, lineno, match, capIndex);
+ scheduleTask(CompileTask(type, description, filename, lineno), 1);
+ return {Status::Done, linkSpecs};
}
return Status::NotHandled;
@@ -150,5 +159,5 @@ void LdParser::flush()
return;
const Task t = m_incompleteTask;
m_incompleteTask.clear();
- emit addTask(t);
+ scheduleTask(t, 1);
}
diff --git a/src/plugins/projectexplorer/ldparser.h b/src/plugins/projectexplorer/ldparser.h
index fc3d959075..56f94f52c7 100644
--- a/src/plugins/projectexplorer/ldparser.h
+++ b/src/plugins/projectexplorer/ldparser.h
@@ -39,7 +39,7 @@ class LdParser : public ProjectExplorer::OutputTaskParser
public:
LdParser();
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
void flush() override;
QRegularExpression m_ranlib;
diff --git a/src/plugins/projectexplorer/linuxiccparser.cpp b/src/plugins/projectexplorer/linuxiccparser.cpp
index 812f10961f..49bdbcdc2a 100644
--- a/src/plugins/projectexplorer/linuxiccparser.cpp
+++ b/src/plugins/projectexplorer/linuxiccparser.cpp
@@ -65,7 +65,7 @@ LinuxIccParser::LinuxIccParser() :
QTC_CHECK(m_pchInfoLine.isValid());
}
-OutputTaskParser::Status LinuxIccParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result LinuxIccParser::handleLine(const QString &line, OutputFormat type)
{
if (type != Utils::StdErrFormat)
return Status::NotHandled;
@@ -81,10 +81,11 @@ OutputTaskParser::Status LinuxIccParser::handleLine(const QString &line, OutputF
type = Task::Error;
else if (category == QLatin1String("warning"))
type = Task::Warning;
- m_temporary = CompileTask(type,
- m_firstLine.cap(6).trimmed(),
- absoluteFilePath(Utils::FilePath::fromUserInput(m_firstLine.cap(1))),
- m_firstLine.cap(2).toInt());
+ const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(m_firstLine.cap(1)));
+ const int lineNo = m_firstLine.cap(2).toInt();
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, m_firstLine, 1);
+ m_temporary = CompileTask(type, m_firstLine.cap(6).trimmed(), filePath, lineNo);
m_lines = 1;
m_expectFirstLine = false;
@@ -107,7 +108,7 @@ OutputTaskParser::Status LinuxIccParser::handleLine(const QString &line, OutputF
}
if (!m_expectFirstLine && line.trimmed().isEmpty()) { // last Line
m_expectFirstLine = true;
- emit addTask(m_temporary, m_lines);
+ scheduleTask(m_temporary, m_lines);
m_temporary = Task();
return Status::Done;
}
@@ -129,7 +130,7 @@ Core::Id LinuxIccParser::id()
return Core::Id("ProjectExplorer.OutputParser.Icc");
}
-QList<OutputTaskParser *> LinuxIccParser::iccParserSuite()
+QList<OutputLineParser *> LinuxIccParser::iccParserSuite()
{
return {new LinuxIccParser, new Internal::LldParser, new LdParser};
}
@@ -140,7 +141,7 @@ void LinuxIccParser::flush()
return;
Task t = m_temporary;
m_temporary.clear();
- emit addTask(t, m_lines, 1);
+ scheduleTask(t, m_lines, 1);
}
#ifdef WITH_TESTS
@@ -237,7 +238,7 @@ void ProjectExplorerPlugin::testLinuxIccOutputParsers_data()
<< (Tasks()
<< CompileTask(Task::Unknown,
"Note: No relevant classes found. No output generated.",
- FilePath::fromUserInput("/home/qtwebkithelpviewer.h"), 0))
+ FilePath::fromUserInput("/home/qtwebkithelpviewer.h"), -1))
<< QString();
}
diff --git a/src/plugins/projectexplorer/linuxiccparser.h b/src/plugins/projectexplorer/linuxiccparser.h
index f5a1dd0096..44ff094c05 100644
--- a/src/plugins/projectexplorer/linuxiccparser.h
+++ b/src/plugins/projectexplorer/linuxiccparser.h
@@ -41,10 +41,10 @@ public:
static Core::Id id();
- static QList<OutputTaskParser *> iccParserSuite();
+ static QList<Utils::OutputLineParser *> iccParserSuite();
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
void flush() override;
QRegExp m_firstLine;
diff --git a/src/plugins/projectexplorer/lldparser.cpp b/src/plugins/projectexplorer/lldparser.cpp
index c938461489..aee20ea795 100644
--- a/src/plugins/projectexplorer/lldparser.cpp
+++ b/src/plugins/projectexplorer/lldparser.cpp
@@ -35,14 +35,14 @@
namespace ProjectExplorer {
namespace Internal {
-OutputTaskParser::Status LldParser::handleLine(const QString &line, Utils::OutputFormat type)
+Utils::OutputLineParser::Result LldParser::handleLine(const QString &line, Utils::OutputFormat type)
{
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));
+ scheduleTask(CompileTask(Task::Error, trimmedLine), 1);
return Status::Done;
}
static const QStringList prefixes{">>> referenced by ", ">>> defined at ", ">>> "};
@@ -65,11 +65,13 @@ OutputTaskParser::Status LldParser::handleLine(const QString &line, Utils::Outpu
else
filePathOffset = prefix.length();
const int filePathLen = locOffset == -1 ? -1 : locOffset - filePathOffset;
- const auto file = Utils::FilePath::fromUserInput(
- trimmedLine.mid(filePathOffset, filePathLen).trimmed());
- emit addTask(CompileTask(Task::Unknown, trimmedLine.mid(4).trimmed(),
- absoluteFilePath(file), lineNo));
- return Status::Done;
+ const auto file = absoluteFilePath(Utils::FilePath::fromUserInput(
+ trimmedLine.mid(filePathOffset, filePathLen).trimmed()));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineNo, filePathOffset, filePathLen);
+ scheduleTask(CompileTask(Task::Unknown, trimmedLine.mid(4).trimmed(),
+ file, lineNo), 1);
+ return {Status::Done, linkSpecs};
}
return Status::NotHandled;
}
diff --git a/src/plugins/projectexplorer/lldparser.h b/src/plugins/projectexplorer/lldparser.h
index d071d0264c..f9bb4388aa 100644
--- a/src/plugins/projectexplorer/lldparser.h
+++ b/src/plugins/projectexplorer/lldparser.h
@@ -32,7 +32,7 @@ namespace Internal {
class LldParser : public OutputTaskParser
{
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
};
} // namespace Internal
diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp
index cd873d5ea7..ec5cafe662 100644
--- a/src/plugins/projectexplorer/makestep.cpp
+++ b/src/plugins/projectexplorer/makestep.cpp
@@ -102,13 +102,17 @@ bool MakeStep::init()
// That is mostly so that rebuild works on an already clean project
setIgnoreReturnValue(isClean());
- setOutputParser(new GnuMakeParser());
- appendOutputParsers(target()->kit()->createOutputParsers());
- outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
-
return AbstractProcessStep::init();
}
+void MakeStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->addLineParser(new GnuMakeParser());
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
void MakeStep::setClean(bool clean)
{
m_clean = clean;
diff --git a/src/plugins/projectexplorer/makestep.h b/src/plugins/projectexplorer/makestep.h
index bd02090bec..decc0b0fcc 100644
--- a/src/plugins/projectexplorer/makestep.h
+++ b/src/plugins/projectexplorer/makestep.h
@@ -54,6 +54,7 @@ public:
void setAvailableBuildTargets(const QStringList &buildTargets);
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
bool buildsTarget(const QString &target) const;
void setBuildTarget(const QString &target, bool on);
diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp
index 151fb52faa..ac68bd3b67 100644
--- a/src/plugins/projectexplorer/msvcparser.cpp
+++ b/src/plugins/projectexplorer/msvcparser.cpp
@@ -105,7 +105,7 @@ Core::Id MsvcParser::id()
return Core::Id("ProjectExplorer.OutputParser.Msvc");
}
-OutputTaskParser::Status MsvcParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result MsvcParser::handleLine(const QString &line, OutputFormat type)
{
if (type == OutputFormat::StdOutFormat) {
QRegularExpressionMatch match = m_additionalInfoRegExp.match(line);
@@ -137,8 +137,9 @@ OutputTaskParser::Status MsvcParser::handleLine(const QString &line, OutputForma
return Status::InProgress;
}
- if (processCompileLine(line))
- return Status::InProgress;
+ const Result res = processCompileLine(line);
+ if (res.status != Status::NotHandled)
+ return res;
if (handleNmakeJomMessage(line, &m_lastTask)) {
m_lines = 1;
return Status::InProgress;
@@ -148,17 +149,20 @@ OutputTaskParser::Status MsvcParser::handleLine(const QString &line, OutputForma
+ 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 */);
+ const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(2)));
+ const int lineNo = match.captured(3).toInt();
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 2);
+ m_lastTask = CompileTask(Task::Unknown, description, filePath, lineNo);
m_lines = 1;
- return Status::InProgress;
+ return {Status::InProgress, linkSpecs};
}
return Status::NotHandled;
}
- if (processCompileLine(line))
- return Status::InProgress;
+ const Result res = processCompileLine(line);
+ if (res.status != Status::NotHandled)
+ return res;
// Jom outputs errors to stderr
if (handleNmakeJomMessage(line, &m_lastTask)) {
m_lines = 1;
@@ -167,20 +171,23 @@ OutputTaskParser::Status MsvcParser::handleLine(const QString &line, OutputForma
return Status::NotHandled;
}
-bool MsvcParser::processCompileLine(const QString &line)
+MsvcParser::Result MsvcParser::processCompileLine(const QString &line)
{
flush();
QRegularExpressionMatch match = m_compileRegExp.match(line);
if (match.hasMatch()) {
QPair<FilePath, int> position = parseFileName(match.captured(1));
+ const FilePath filePath = absoluteFilePath(position.first);
m_lastTask = CompileTask(taskType(match.captured(2)),
match.captured(3) + match.captured(4).trimmed(), // description
- absoluteFilePath(position.first), position.second);
+ filePath, position.second);
m_lines = 1;
- return true;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match, 1);
+ return {Status::InProgress, linkSpecs};
}
- return false;
+ return Status::NotHandled;
}
void MsvcParser::flush()
@@ -190,7 +197,7 @@ void MsvcParser::flush()
Task t = m_lastTask;
m_lastTask.clear();
- emit addTask(t, m_lines, 1);
+ scheduleTask(t, m_lines, 1);
}
// --------------------------------------------------------------------------
@@ -220,7 +227,7 @@ static inline bool isClangCodeMarker(const QString &trimmedLine)
[] (QChar c) { return c != ' ' && c != '^' && c != '~'; });
}
-OutputTaskParser::Status ClangClParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result ClangClParser::handleLine(const QString &line, OutputFormat type)
{
if (type == StdOutFormat) {
if (handleNmakeJomMessage(line, &m_lastTask)) {
@@ -257,7 +264,9 @@ OutputTaskParser::Status ClangClParser::handleLine(const QString &line, OutputFo
m_lastTask = CompileTask(taskType(match.captured(2)), match.captured(3).trimmed(),
absoluteFilePath(position.first), position.second);
m_linkedLines = 1;
- return Status::InProgress;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match, 1);
+ return {Status::InProgress, linkSpecs};
}
if (!m_lastTask.isNull()) {
@@ -278,7 +287,7 @@ OutputTaskParser::Status ClangClParser::handleLine(const QString &line, OutputFo
void ClangClParser::flush()
{
if (!m_lastTask.isNull()) {
- emit addTask(m_lastTask, m_linkedLines, 1);
+ scheduleTask(m_lastTask, m_linkedLines, 1);
m_lastTask.clear();
}
}
diff --git a/src/plugins/projectexplorer/msvcparser.h b/src/plugins/projectexplorer/msvcparser.h
index 3f71263ee8..f2b8d47d97 100644
--- a/src/plugins/projectexplorer/msvcparser.h
+++ b/src/plugins/projectexplorer/msvcparser.h
@@ -43,10 +43,10 @@ public:
static Core::Id id();
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
void flush() override;
- bool processCompileLine(const QString &line);
+ Result processCompileLine(const QString &line);
QRegularExpression m_compileRegExp;
QRegularExpression m_additionalInfoRegExp;
@@ -63,7 +63,7 @@ public:
ClangClParser();
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
void flush() override;
const QRegularExpression m_compileRegExp;
diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp
index f486a52202..a2332739bc 100644
--- a/src/plugins/projectexplorer/msvctoolchain.cpp
+++ b/src/plugins/projectexplorer/msvctoolchain.cpp
@@ -1169,7 +1169,7 @@ void MsvcToolChain::rescanForCompiler()
});
}
-QList<OutputTaskParser *> MsvcToolChain::createOutputParsers() const
+QList<OutputLineParser *> MsvcToolChain::createOutputParsers() const
{
return {new MsvcParser};
}
@@ -1656,7 +1656,7 @@ QStringList ClangClToolChain::suggestedMkspecList() const
return {mkspec, "win32-clang-msvc"};
}
-QList<OutputTaskParser *> ClangClToolChain::createOutputParsers() const
+QList<OutputLineParser *> ClangClToolChain::createOutputParsers() const
{
return {new ClangClParser};
}
diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h
index 4d40c0a25d..7731598cb1 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;
- QList<OutputTaskParser *> createOutputParsers() const override;
+ QList<Utils::OutputLineParser *> createOutputParsers() 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;
- QList<OutputTaskParser *> createOutputParsers() const override;
+ QList<Utils::OutputLineParser *> createOutputParsers() 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 3ea1dcc119..9a1f11a0ba 100644
--- a/src/plugins/projectexplorer/osparser.cpp
+++ b/src/plugins/projectexplorer/osparser.cpp
@@ -36,18 +36,18 @@ OsParser::OsParser()
setObjectName(QLatin1String("OsParser"));
}
-OutputTaskParser::Status OsParser::handleLine(const QString &line, Utils::OutputFormat type)
+Utils::OutputLineParser::Result OsParser::handleLine(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(
+ scheduleTask(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.")));
+ "starting a build.")), 1);
m_hasFatalError = true;
return Status::Done;
}
@@ -57,7 +57,7 @@ OutputTaskParser::Status OsParser::handleLine(const QString &line, Utils::Output
if (Utils::HostOsInfo::isLinuxHost()) {
const QString trimmed = line.trimmed();
if (trimmed.contains(QLatin1String(": error while loading shared libraries:"))) {
- emit addTask(CompileTask(Task::Error, trimmed));
+ scheduleTask(CompileTask(Task::Error, trimmed), 1);
return Status::Done;
}
}
diff --git a/src/plugins/projectexplorer/osparser.h b/src/plugins/projectexplorer/osparser.h
index f33551648a..d3e97eee6e 100644
--- a/src/plugins/projectexplorer/osparser.h
+++ b/src/plugins/projectexplorer/osparser.h
@@ -41,7 +41,7 @@ public:
OsParser();
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(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 8caec11242..8516a84de0 100644
--- a/src/plugins/projectexplorer/outputparser_test.cpp
+++ b/src/plugins/projectexplorer/outputparser_test.cpp
@@ -24,7 +24,9 @@
****************************************************************************/
#include "outputparser_test.h"
+#include "projectexplorer.h"
#include "task.h"
+#include "taskhub.h"
#if defined(WITH_TESTS)
@@ -41,11 +43,16 @@ static inline QByteArray msgFileComparisonFail(const Utils::FilePath &f1, const
// test functions:
OutputParserTester::OutputParserTester()
{
- connect(this, &IOutputParser::addTask, this, [this](const Task &t) {
+ connect(TaskHub::instance(), &TaskHub::taskAdded, this, [this](const Task &t) {
m_receivedTasks.append(t);
});
}
+OutputParserTester::~OutputParserTester()
+{
+ TaskHub::instance()->disconnect(this);
+}
+
void OutputParserTester::testParsing(const QString &lines,
Channel inputChannel,
Tasks tasks,
@@ -60,9 +67,9 @@ void OutputParserTester::testParsing(const QString &lines,
reset();
if (inputChannel == STDOUT)
- handleStdout(lines + '\n');
+ appendMessage(lines + '\n', Utils::StdOutFormat);
else
- handleStderr(lines + '\n');
+ appendMessage(lines + '\n', Utils::StdErrFormat);
flush();
// delete the parser(s) to test
@@ -102,7 +109,7 @@ TestTerminator::TestTerminator(OutputParserTester *t) :
m_tester(t)
{ }
-OutputTaskParser::Status TestTerminator::handleLine(const QString &line, Utils::OutputFormat type)
+Utils::OutputLineParser::Result TestTerminator::handleLine(const QString &line, Utils::OutputFormat type)
{
QTC_CHECK(line.endsWith('\n'));
if (type == Utils::StdOutFormat)
@@ -112,6 +119,64 @@ OutputTaskParser::Status TestTerminator::handleLine(const QString &line, Utils::
return Status::Done;
}
+void ProjectExplorerPlugin::testAnsiFilterOutputParser_data()
+{
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<OutputParserTester::Channel>("inputChannel");
+ QTest::addColumn<QString>("childStdOutLines");
+ QTest::addColumn<QString>("childStdErrLines");
+ QTest::addColumn<QString>("outputLines");
+
+ QTest::newRow("pass-through stdout")
+ << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
+ << QString::fromLatin1("Sometext\n") << QString();
+ QTest::newRow("pass-through stderr")
+ << QString::fromLatin1("Sometext") << OutputParserTester::STDERR
+ << QString() << QString::fromLatin1("Sometext\n");
+
+ QString input = QString::fromLatin1("te") + QChar(27) + QString::fromLatin1("Nst");
+ QTest::newRow("ANSI: ESC-N")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
+ input = QString::fromLatin1("te") + QChar(27) + QLatin1String("^ignored") + QChar(27) + QLatin1String("\\st");
+ QTest::newRow("ANSI: ESC-^ignoredESC-\\")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
+ input = QString::fromLatin1("te") + QChar(27) + QLatin1String("]0;ignored") + QChar(7) + QLatin1String("st");
+ QTest::newRow("ANSI: window title change")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
+ input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[Ast");
+ QTest::newRow("ANSI: cursor up")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
+ input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[2Ast");
+ QTest::newRow("ANSI: cursor up (with int parameter)")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
+ input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[2;3Hst");
+ QTest::newRow("ANSI: position cursor")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
+ input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[31;1mst");
+ QTest::newRow("ANSI: bold red")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
+}
+
+void ProjectExplorerPlugin::testAnsiFilterOutputParser()
+{
+ OutputParserTester testbench;
+ QFETCH(QString, input);
+ QFETCH(OutputParserTester::Channel, inputChannel);
+ QFETCH(QString, childStdOutLines);
+ QFETCH(QString, childStdErrLines);
+
+ testbench.testParsing(input, inputChannel,
+ Tasks(), childStdOutLines, childStdErrLines,
+ QString());
+}
+
} // namespace ProjectExplorer
#endif
diff --git a/src/plugins/projectexplorer/outputparser_test.h b/src/plugins/projectexplorer/outputparser_test.h
index 86dd048134..b41b9a1f87 100644
--- a/src/plugins/projectexplorer/outputparser_test.h
+++ b/src/plugins/projectexplorer/outputparser_test.h
@@ -36,7 +36,7 @@ namespace ProjectExplorer {
class TestTerminator;
-class PROJECTEXPLORER_EXPORT OutputParserTester : public IOutputParser
+class PROJECTEXPLORER_EXPORT OutputParserTester : public Utils::OutputFormatter
{
Q_OBJECT
@@ -47,6 +47,7 @@ public:
};
OutputParserTester();
+ ~OutputParserTester();
// test functions:
void testParsing(const QString &lines, Channel inputChannel,
@@ -81,7 +82,7 @@ public:
TestTerminator(OutputParserTester *t);
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(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 b1a38607e3..5a53574d93 100644
--- a/src/plugins/projectexplorer/parseissuesdialog.cpp
+++ b/src/plugins/projectexplorer/parseissuesdialog.cpp
@@ -136,13 +136,13 @@ ParseIssuesDialog::~ParseIssuesDialog()
}
static void parse(QFutureInterface<void> &future, const QString &output,
- const std::unique_ptr<IOutputParser> &parser, bool isStderr)
+ const std::unique_ptr<Utils::OutputFormatter> &parser, bool isStderr)
{
const QStringList lines = output.split('\n');
future.setProgressRange(0, lines.count());
- const auto parserFunc = isStderr ? &IOutputParser::handleStderr : &IOutputParser::handleStdout;
+ const Utils::OutputFormat format = isStderr ? Utils::StdErrFormat : Utils::StdOutFormat;
for (const QString &line : lines) {
- (parser.get()->*parserFunc)(line + '\n');
+ parser->appendMessage(line + '\n', format);
future.setProgressValue(future.progressValue() + 1);
if (future.isCanceled())
return;
@@ -151,17 +151,17 @@ static void parse(QFutureInterface<void> &future, const QString &output,
void ParseIssuesDialog::accept()
{
- const QList<OutputTaskParser *> lineParsers = d->kitChooser.currentKit()->createOutputParsers();
+ const QList<Utils::OutputLineParser *> 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);
+ std::unique_ptr<Utils::OutputFormatter> parser(new Utils::OutputFormatter);
parser->setLineParsers(lineParsers);
if (d->clearTasksCheckBox.isChecked())
TaskHub::clearTasks();
- connect(parser.get(), &IOutputParser::addTask, [](const Task &t) { TaskHub::addTask(t); });
const QFuture<void> f = Utils::runAsync(&parse, d->compileOutputEdit.toPlainText(),
std::move(parser), d->stderrCheckBox.isChecked());
Core::ProgressManager::addTask(f, tr("Parsing build output"),
diff --git a/src/plugins/projectexplorer/processstep.cpp b/src/plugins/projectexplorer/processstep.cpp
index ea8de1cb3b..035b816ff0 100644
--- a/src/plugins/projectexplorer/processstep.cpp
+++ b/src/plugins/projectexplorer/processstep.cpp
@@ -35,6 +35,7 @@
#include "target.h"
#include <utils/fileutils.h>
+#include <utils/outputformatter.h>
using namespace Utils;
@@ -53,6 +54,7 @@ public:
ProcessStep(BuildStepList *bsl, Core::Id id);
bool init() final;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter);
void setupProcessParameters(ProcessParameters *pp);
BaseStringAspect *m_command;
@@ -100,10 +102,15 @@ ProcessStep::ProcessStep(BuildStepList *bsl, Core::Id id)
bool ProcessStep::init()
{
setupProcessParameters(processParameters());
- appendOutputParsers(target()->kit()->createOutputParsers());
return AbstractProcessStep::init();
}
+void ProcessStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
void ProcessStep::setupProcessParameters(ProcessParameters *pp)
{
QString workingDirectory = m_workingDirectory->value();
diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro
index 4f9b5dd4f7..4a8f962198 100644
--- a/src/plugins/projectexplorer/projectexplorer.pro
+++ b/src/plugins/projectexplorer/projectexplorer.pro
@@ -11,7 +11,6 @@ HEADERS += projectexplorer.h \
abi.h \
abiwidget.h \
addrunconfigdialog.h \
- ansifilterparser.h \
buildaspects.h \
buildinfo.h \
buildpropertiessettings.h \
@@ -172,7 +171,6 @@ SOURCES += projectexplorer.cpp \
abi.cpp \
abiwidget.cpp \
addrunconfigdialog.cpp \
- ansifilterparser.cpp \
buildaspects.cpp \
buildinfo.cpp \
buildpropertiessettingspage.cpp \
diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs
index 6398533ca4..38efedd210 100644
--- a/src/plugins/projectexplorer/projectexplorer.qbs
+++ b/src/plugins/projectexplorer/projectexplorer.qbs
@@ -27,7 +27,6 @@ Project {
"addrunconfigdialog.cpp", "addrunconfigdialog.h",
"allprojectsfilter.cpp", "allprojectsfilter.h",
"allprojectsfind.cpp", "allprojectsfind.h",
- "ansifilterparser.cpp", "ansifilterparser.h",
"applicationlauncher.cpp", "applicationlauncher.h",
"appoutputpane.cpp", "appoutputpane.h",
"baseprojectwizarddialog.cpp", "baseprojectwizarddialog.h",
diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h
index cc98793bde..b2dbc7ca9a 100644
--- a/src/plugins/projectexplorer/toolchain.h
+++ b/src/plugins/projectexplorer/toolchain.h
@@ -47,6 +47,8 @@
#include <functional>
#include <memory>
+namespace Utils { class OutputLineParser; }
+
namespace ProjectExplorer {
namespace Internal { class ToolChainPrivate; }
@@ -64,7 +66,6 @@ QString languageId(Language l);
} // namespace Deprecated
class Abi;
-class OutputTaskParser;
class ToolChainConfigWidget;
class ToolChainFactory;
class Kit;
@@ -150,7 +151,7 @@ public:
Core::Id language() const;
virtual Utils::FilePath compilerCommand() const = 0;
- virtual QList<OutputTaskParser *> createOutputParsers() const = 0;
+ virtual QList<Utils::OutputLineParser *> createOutputParsers() const = 0;
virtual bool operator ==(const ToolChain &) const;
diff --git a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
index 43c9655d83..dd6e540b1a 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"); }
- QList<OutputTaskParser *> createOutputParsers() const override { return {}; }
+ QList<OutputLineParser *> createOutputParsers() 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 4b5d9e4c7e..9b6486e5d5 100644
--- a/src/plugins/projectexplorer/xcodebuildparser.cpp
+++ b/src/plugins/projectexplorer/xcodebuildparser.cpp
@@ -52,7 +52,7 @@ XcodebuildParser::XcodebuildParser()
QTC_CHECK(m_buildRe.isValid());
}
-OutputTaskParser::Status XcodebuildParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result XcodebuildParser::handleLine(const QString &line, OutputFormat type)
{
const QString lne = rightTrimmed(line);
if (type == StdOutFormat) {
@@ -69,12 +69,16 @@ OutputTaskParser::Status XcodebuildParser::handleLine(const QString &line, Outpu
return Status::Done;
}
if (lne.endsWith(QLatin1String(signatureChangeEndsWithPattern))) {
+ const int filePathEndPos = lne.size()
+ - QLatin1String(signatureChangeEndsWithPattern).size();
CompileTask task(Task::Warning,
tr("Replacing signature"),
absoluteFilePath(FilePath::fromString(
- lne.left(lne.size() - QLatin1String(signatureChangeEndsWithPattern).size()))));
- emit addTask(task, 1);
- return Status::Done;
+ lne.left(filePathEndPos))));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, task.file, task.line, 0, filePathEndPos);
+ scheduleTask(task, 1);
+ return {Status::Done, linkSpecs};
}
}
return Status::NotHandled;
@@ -83,7 +87,7 @@ OutputTaskParser::Status XcodebuildParser::handleLine(const QString &line, Outpu
++m_fatalErrorCount;
m_xcodeBuildParserState = UnknownXcodebuildState;
// unfortunately the m_lastTarget, m_lastProject might not be in sync
- emit addTask(CompileTask(Task::Error, tr("Xcodebuild failed.")));
+ scheduleTask(CompileTask(Task::Error, tr("Xcodebuild failed.")), 1);
}
if (m_xcodeBuildParserState == OutsideXcodebuild)
return Status::NotHandled;
diff --git a/src/plugins/projectexplorer/xcodebuildparser.h b/src/plugins/projectexplorer/xcodebuildparser.h
index 5c91315d74..9342cd3785 100644
--- a/src/plugins/projectexplorer/xcodebuildparser.h
+++ b/src/plugins/projectexplorer/xcodebuildparser.h
@@ -47,7 +47,7 @@ public:
XcodebuildParser();
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
bool hasDetectedRedirection() const override;
bool hasFatalErrors() const override { return m_fatalErrorCount > 0; }
diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp
index 0e43cb3eea..42dad98cb1 100644
--- a/src/plugins/python/pythonrunconfiguration.cpp
+++ b/src/plugins/python/pythonrunconfiguration.cpp
@@ -126,12 +126,6 @@ private:
return true;
}
- void reset() override
- {
- m_inTraceBack = false;
- m_tasks.clear();
- }
-
const QRegularExpression filePattern;
QList<Task> m_tasks;
bool m_inTraceBack;
diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
index d403ad0589..062f48e15b 100644
--- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
+++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
@@ -34,12 +34,12 @@
#include <coreplugin/icore.h>
#include <coreplugin/variablechooser.h>
#include <projectexplorer/buildsteplist.h>
-#include <projectexplorer/ioutputparser.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtversionmanager.h>
#include <utils/macroexpander.h>
+#include <utils/outputformatter.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
@@ -155,7 +155,6 @@ QbsBuildStep::~QbsBuildStep()
doCancel();
if (m_session)
m_session->disconnect(this);
- delete m_parser;
}
bool QbsBuildStep::init()
@@ -168,11 +167,6 @@ bool QbsBuildStep::init()
if (!bc)
return false;
- delete m_parser;
- 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();
m_products = bc->products();
@@ -180,6 +174,12 @@ bool QbsBuildStep::init()
return true;
}
+void QbsBuildStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ BuildStep::setupOutputFormatter(formatter);
+}
+
void QbsBuildStep::doRun()
{
// We need a pre-build parsing step in order not to lose project file changes done
@@ -371,35 +371,24 @@ void QbsBuildStep::handleProcessResult(
const QStringList &stdErr,
bool success)
{
+ Q_UNUSED(workingDir);
const bool hasOutput = !stdOut.isEmpty() || !stdErr.isEmpty();
if (success && !hasOutput)
return;
- if (m_parser)
- m_parser->addSearchDir(workingDir);
emit addOutput(executable.toUserOutput() + ' ' + QtcProcess::joinArgs(arguments),
OutputFormat::Stdout);
- for (const QString &line : stdErr) {
- if (m_parser)
- m_parser->handleStderr(line + '\n');
+ for (const QString &line : stdErr)
emit addOutput(line, OutputFormat::Stderr);
- }
- for (const QString &line : stdOut) {
- if (m_parser)
- m_parser->handleStdout(line + '\n');
+ for (const QString &line : stdOut)
emit addOutput(line, OutputFormat::Stdout);
- }
- if (m_parser) {
- m_parser->flush();
- m_parser->dropSearchDir(workingDir);
- }
}
void QbsBuildStep::createTaskAndOutput(ProjectExplorer::Task::TaskType type, const QString &message,
const QString &file, int line)
{
- emit addTask(CompileTask(type, message, FilePath::fromString(file), line), 1);
emit addOutput(message, OutputFormat::Stdout);
+ emit addTask(CompileTask(type, message, FilePath::fromString(file), line), 1);
}
QString QbsBuildStep::buildVariant() const
diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.h b/src/plugins/qbsprojectmanager/qbsbuildstep.h
index f0906936b6..d257662bdb 100644
--- a/src/plugins/qbsprojectmanager/qbsbuildstep.h
+++ b/src/plugins/qbsprojectmanager/qbsbuildstep.h
@@ -30,7 +30,6 @@
#include <projectexplorer/buildstep.h>
#include <projectexplorer/task.h>
-namespace ProjectExplorer { class IOutputParser; }
namespace Utils { class FancyLineEdit; }
namespace QbsProjectManager {
@@ -81,6 +80,7 @@ signals:
private:
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
void doRun() override;
void doCancel() override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
@@ -134,7 +134,6 @@ private:
QString m_currentTask;
int m_maxProgress;
bool m_lastWasSuccess;
- ProjectExplorer::IOutputParser *m_parser = nullptr;
bool m_parsingProject = false;
bool m_parsingAfterBuild = false;
diff --git a/src/plugins/qbsprojectmanager/qbscleanstep.cpp b/src/plugins/qbsprojectmanager/qbscleanstep.cpp
index 07adf568d2..44d3372896 100644
--- a/src/plugins/qbsprojectmanager/qbscleanstep.cpp
+++ b/src/plugins/qbsprojectmanager/qbscleanstep.cpp
@@ -160,8 +160,8 @@ void QbsCleanStep::handleProgress(int value)
void QbsCleanStep::createTaskAndOutput(ProjectExplorer::Task::TaskType type, const QString &message, const QString &file, int line)
{
- emit addTask(CompileTask(type, message, Utils::FilePath::fromString(file), line), 1);
emit addOutput(message, OutputFormat::Stdout);
+ emit addTask(CompileTask(type, message, Utils::FilePath::fromString(file), line), 1);
}
// --------------------------------------------------------------------
diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp
index f3e3164e1e..9ad460e48e 100644
--- a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp
+++ b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp
@@ -202,9 +202,8 @@ void QbsInstallStep::handleProgress(int value)
void QbsInstallStep::createTaskAndOutput(Task::TaskType type, const QString &message,
const Utils::FilePath &file, int line)
{
- const CompileTask task(type, message, file, line);
- emit addTask(task, 1);
emit addOutput(message, OutputFormat::Stdout);
+ emit addTask(CompileTask(type, message, file, line), 1);
}
void QbsInstallStep::setRemoveFirst(bool rf)
diff --git a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp
index 6ff538f70a..8a105d6666 100644
--- a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp
@@ -164,25 +164,6 @@ bool QmakeMakeStep::init()
pp->setCommandLine(makeCmd);
pp->resolveAll();
- setOutputParser(new ProjectExplorer::GnuMakeParser());
- ToolChain *tc = ToolChainKitAspect::cxxToolChain(target()->kit());
- OutputTaskParser *xcodeBuildParser = nullptr;
- if (tc && tc->targetAbi().os() == Abi::DarwinOS) {
- xcodeBuildParser = new XcodebuildParser;
- appendOutputParser(xcodeBuildParser);
- }
- QList<OutputTaskParser *> 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 (OutputTaskParser * const p : qAsConst(additionalParsers))
- p->setRedirectionDetector(xcodeBuildParser);
- }
- appendOutputParsers(additionalParsers);
- outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
-
auto rootNode = dynamic_cast<QmakeProFileNode *>(project()->rootProjectNode());
QTC_ASSERT(rootNode, return false);
m_scriptTarget = rootNode->projectType() == ProjectType::ScriptTemplate;
@@ -199,6 +180,30 @@ bool QmakeMakeStep::init()
return AbstractProcessStep::init();
}
+void QmakeMakeStep::setupOutputFormatter(Utils::OutputFormatter *formatter)
+{
+ formatter->addLineParser(new ProjectExplorer::GnuMakeParser());
+ ToolChain *tc = ToolChainKitAspect::cxxToolChain(target()->kit());
+ OutputTaskParser *xcodeBuildParser = nullptr;
+ if (tc && tc->targetAbi().os() == Abi::DarwinOS) {
+ xcodeBuildParser = new XcodebuildParser;
+ formatter->addLineParser(xcodeBuildParser);
+ }
+ QList<Utils::OutputLineParser *> 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 (Utils::OutputLineParser * const p : qAsConst(additionalParsers))
+ p->setRedirectionDetector(xcodeBuildParser);
+ }
+ formatter->addLineParsers(additionalParsers);
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
void QmakeMakeStep::doRun()
{
if (m_scriptTarget || m_ignoredNonTopLevelBuild) {
diff --git a/src/plugins/qmakeprojectmanager/qmakemakestep.h b/src/plugins/qmakeprojectmanager/qmakemakestep.h
index 29e5898e01..ea4fc72b66 100644
--- a/src/plugins/qmakeprojectmanager/qmakemakestep.h
+++ b/src/plugins/qmakeprojectmanager/qmakemakestep.h
@@ -52,6 +52,7 @@ public:
private:
void finish(bool success) override;
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
void doRun() override;
QStringList displayArguments() const override;
diff --git a/src/plugins/qmakeprojectmanager/qmakeparser.cpp b/src/plugins/qmakeprojectmanager/qmakeparser.cpp
index 20633f397d..64e08bf675 100644
--- a/src/plugins/qmakeprojectmanager/qmakeparser.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeparser.cpp
@@ -40,7 +40,7 @@ QMakeParser::QMakeParser() : m_error(QLatin1String("^(.+):(\\d+):\\s(.+)$"))
m_error.setMinimal(true);
}
-OutputTaskParser::Status QMakeParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result QMakeParser::handleLine(const QString &line, OutputFormat type)
{
if (type != Utils::StdErrFormat)
return Status::NotHandled;
@@ -49,11 +49,14 @@ OutputTaskParser::Status QMakeParser::handleLine(const QString &line, OutputForm
QString fileName = m_error.cap(1);
Task::TaskType type = Task::Error;
const QString description = m_error.cap(3);
+ int fileNameOffset = m_error.pos(1);
if (fileName.startsWith(QLatin1String("WARNING: "))) {
type = Task::Warning;
fileName = fileName.mid(9);
+ fileNameOffset += 9;
} else if (fileName.startsWith(QLatin1String("ERROR: "))) {
fileName = fileName.mid(7);
+ fileNameOffset += 7;
}
if (description.startsWith(QLatin1String("note:"), Qt::CaseInsensitive))
type = Task::Unknown;
@@ -61,23 +64,25 @@ OutputTaskParser::Status QMakeParser::handleLine(const QString &line, OutputForm
type = Task::Warning;
else if (description.startsWith(QLatin1String("error:"), Qt::CaseInsensitive))
type = Task::Error;
- emit addTask(BuildSystemTask(type,
- description,
- absoluteFilePath(FilePath::fromUserInput(fileName)),
- m_error.cap(2).toInt() /* line */),
- 1);
- return Status::Done;
+
+ BuildSystemTask t(type, description, absoluteFilePath(FilePath::fromUserInput(fileName)),
+ m_error.cap(2).toInt() /* line */);
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, t.file, t.line, fileNameOffset,
+ fileName.length());
+ scheduleTask(t, 1);
+ return {Status::Done, linkSpecs};
}
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);
+ scheduleTask(BuildSystemTask(Task::Error, description), 1);
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);
+ scheduleTask(BuildSystemTask(Task::Warning, description), 1);
return Status::Done;
}
return Status::NotHandled;
@@ -174,7 +179,7 @@ void QmakeProjectManagerPlugin::testQmakeOutputParsers_data()
<< (Tasks()
<< BuildSystemTask(Task::Unknown,
"Note: No relevant classes found. No output generated.",
- FilePath::fromUserInput("/home/qtwebkithelpviewer.h"), 0))
+ FilePath::fromUserInput("/home/qtwebkithelpviewer.h"), -1))
<< QString();
}
diff --git a/src/plugins/qmakeprojectmanager/qmakeparser.h b/src/plugins/qmakeprojectmanager/qmakeparser.h
index 14c5b20d88..210e5e576c 100644
--- a/src/plugins/qmakeprojectmanager/qmakeparser.h
+++ b/src/plugins/qmakeprojectmanager/qmakeparser.h
@@ -41,7 +41,7 @@ public:
QMakeParser();
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
QRegExp m_error;
};
diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp
index 7d1a418249..424e12f543 100644
--- a/src/plugins/qmakeprojectmanager/qmakestep.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp
@@ -225,8 +225,6 @@ bool QMakeStep::init()
pp->setWorkingDirectory(workingDirectory);
pp->setEnvironment(qmakeBc->environment());
- setOutputParser(new QMakeParser);
-
QmakeProFileNode *node = static_cast<QmakeProFileNode *>(qmakeBc->project()->rootProjectNode());
if (qmakeBc->subNodeBuild())
node = qmakeBc->subNodeBuild();
@@ -254,6 +252,13 @@ bool QMakeStep::init()
return AbstractProcessStep::init();
}
+void QMakeStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->addLineParser(new QMakeParser);
+ m_outputFormatter = formatter;
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
void QMakeStep::doRun()
{
if (m_scriptTemplate) {
@@ -332,7 +337,7 @@ void QMakeStep::runNextCommand()
case State::IDLE:
return;
case State::RUN_QMAKE:
- setOutputParser(new QMakeParser);
+ m_outputFormatter->setLineParsers({new QMakeParser});
m_nextState = (m_runMakeQmake ? State::RUN_MAKE_QMAKE_ALL : State::POST_PROCESS);
startOneCommand(m_qmakeCommand);
return;
@@ -340,7 +345,7 @@ void QMakeStep::runNextCommand()
{
auto *parser = new GnuMakeParser;
parser->addSearchDir(processParameters()->workingDirectory());
- setOutputParser(parser);
+ m_outputFormatter->setLineParsers({parser});
m_nextState = State::POST_PROCESS;
startOneCommand(m_makeCommand);
}
diff --git a/src/plugins/qmakeprojectmanager/qmakestep.h b/src/plugins/qmakeprojectmanager/qmakestep.h
index 6475757e16..05710e1083 100644
--- a/src/plugins/qmakeprojectmanager/qmakestep.h
+++ b/src/plugins/qmakeprojectmanager/qmakestep.h
@@ -121,6 +121,7 @@ public:
QmakeBuildConfiguration *qmakeBuildConfiguration() const;
QmakeBuildSystem *qmakeBuildSystem() const;
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
void doRun() override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void setForced(bool b);
@@ -192,6 +193,7 @@ private:
bool m_runMakeQmake = false;
bool m_scriptTemplate = false;
QStringList m_selectedAbis;
+ Utils::OutputFormatter *m_outputFormatter = nullptr;
};
diff --git a/src/plugins/qtsupport/qtkitinformation.cpp b/src/plugins/qtsupport/qtkitinformation.cpp
index 61f554b99d..070f8c4860 100644
--- a/src/plugins/qtsupport/qtkitinformation.cpp
+++ b/src/plugins/qtsupport/qtkitinformation.cpp
@@ -288,7 +288,7 @@ void QtKitAspect::addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environ
version->addToEnvironment(k, env);
}
-QList<OutputTaskParser *> QtKitAspect::createOutputParsers(const Kit *k) const
+QList<Utils::OutputLineParser *> QtKitAspect::createOutputParsers(const Kit *k) const
{
if (qtVersion(k))
return {new Internal::QtTestParser, new QtParser};
diff --git a/src/plugins/qtsupport/qtkitinformation.h b/src/plugins/qtsupport/qtkitinformation.h
index dacd3e6f51..b494ec09a4 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;
- QList<ProjectExplorer::OutputTaskParser *> createOutputParsers(const ProjectExplorer::Kit *k) const override;
+ QList<Utils::OutputLineParser *> 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/qtoutputformatter.cpp b/src/plugins/qtsupport/qtoutputformatter.cpp
index 66ebffc433..9c1803bf3d 100644
--- a/src/plugins/qtsupport/qtoutputformatter.cpp
+++ b/src/plugins/qtsupport/qtoutputformatter.cpp
@@ -79,7 +79,7 @@ public:
FileInProjectFinder projectFinder;
};
-class QtOutputLineParser : public QObject, public OutputLineParser
+class QtOutputLineParser : public OutputLineParser
{
public:
explicit QtOutputLineParser(Target *target);
@@ -482,11 +482,11 @@ void QtSupportPlugin::testQtOutputFormatter_appendMessage()
QFETCH(QTextCharFormat, inputFormat);
QFETCH(QTextCharFormat, outputFormat);
if (outputFormat == QTextCharFormat())
- outputFormat = formatter.charFormat(DebugFormat);
+ outputFormat = formatter.charFormat(StdOutFormat);
if (inputFormat != QTextCharFormat())
formatter.overrideTextCharFormat(inputFormat);
- formatter.appendMessage(inputText, DebugFormat);
+ formatter.appendMessage(inputText, StdOutFormat);
formatter.flush();
QCOMPARE(edit.toPlainText(), outputText);
@@ -509,7 +509,7 @@ void QtSupportPlugin::testQtOutputFormatter_appendMixedAssertAndAnsi()
"file://test.cpp:123 "
"Blue\n";
- formatter.appendMessage(inputText, DebugFormat);
+ formatter.appendMessage(inputText, StdOutFormat);
QCOMPARE(edit.toPlainText(), outputText);
diff --git a/src/plugins/qtsupport/qtparser.cpp b/src/plugins/qtsupport/qtparser.cpp
index 1c53feb247..b376e9911c 100644
--- a/src/plugins/qtsupport/qtparser.cpp
+++ b/src/plugins/qtsupport/qtparser.cpp
@@ -28,9 +28,18 @@
#include <projectexplorer/task.h>
#include <projectexplorer/projectexplorerconstants.h>
-using namespace QtSupport;
+#include <QFileInfo>
+
+#ifdef WITH_TESTS
+#include "qtsupportplugin.h"
+#include <projectexplorer/outputparser_test.h>
+#include <QTest>
+#endif
+
using namespace ProjectExplorer;
+namespace QtSupport {
+
// opt. drive letter + filename: (2 brackets)
#define FILE_PATTERN "^(([A-Za-z]:)?[^:]+\\.[^:]+)"
@@ -43,7 +52,7 @@ QtParser::QtParser() :
m_translationRegExp.setMinimal(true);
}
-OutputTaskParser::Status QtParser::handleLine(const QString &line, Utils::OutputFormat type)
+Utils::OutputLineParser::Result QtParser::handleLine(const QString &line, Utils::OutputFormat type)
{
if (type != Utils::StdErrFormat)
return Status::NotHandled;
@@ -60,20 +69,25 @@ OutputTaskParser::Status QtParser::handleLine(const QString &line, Utils::Output
type = Task::Warning;
if (level.compare(QLatin1String("Note"), Qt::CaseInsensitive) == 0)
type = Task::Unknown;
- CompileTask task(type, m_mocRegExp.cap(5).trimmed() /* description */,
- absoluteFilePath(Utils::FilePath::fromUserInput(m_mocRegExp.cap(1))),
- lineno);
- emit addTask(task, 1);
- return Status::Done;
+ LinkSpecs linkSpecs;
+ const Utils::FilePath file
+ = absoluteFilePath(Utils::FilePath::fromUserInput(m_mocRegExp.cap(1)));
+ addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineno, m_mocRegExp, 1);
+ CompileTask task(type, m_mocRegExp.cap(5).trimmed() /* description */, file, lineno);
+ scheduleTask(task, 1);
+ return {Status::Done, linkSpecs};
}
if (m_translationRegExp.indexIn(lne) > -1) {
Task::TaskType type = Task::Warning;
if (m_translationRegExp.cap(1) == QLatin1String("Error"))
type = Task::Error;
- CompileTask task(type, m_translationRegExp.cap(2),
- absoluteFilePath(Utils::FilePath::fromUserInput(m_translationRegExp.cap(3))));
- emit addTask(task, 1);
- return Status::Done;
+ LinkSpecs linkSpecs;
+ const Utils::FilePath file
+ = absoluteFilePath(Utils::FilePath::fromUserInput(m_translationRegExp.cap(3)));
+ addLinkSpecForAbsoluteFilePath(linkSpecs, file, 0, m_translationRegExp, 3);
+ CompileTask task(type, m_translationRegExp.cap(2), file);
+ scheduleTask(task, 1);
+ return {Status::Done, linkSpecs};
}
return Status::NotHandled;
}
@@ -81,14 +95,7 @@ OutputTaskParser::Status QtParser::handleLine(const QString &line, Utils::Output
// Unit tests:
#ifdef WITH_TESTS
-# include <QTest>
-
-# include "qtsupportplugin.h"
-# include <projectexplorer/projectexplorerconstants.h>
-# include <projectexplorer/outputparser_test.h>
-
-using namespace ProjectExplorer;
-using namespace QtSupport::Internal;
+namespace Internal {
void QtSupportPlugin::testQtOutputParser_data()
{
@@ -139,7 +146,7 @@ void QtSupportPlugin::testQtOutputParser_data()
<< QString() << QString()
<< (Tasks() << CompileTask(Task::Warning,
QLatin1String("No relevant classes found. No output generated."),
- Utils::FilePath::fromUserInput(QLatin1String("..\\untitled\\errorfile.h")), 0))
+ Utils::FilePath::fromUserInput(QLatin1String("..\\untitled\\errorfile.h")), -1))
<< QString();
QTest::newRow("moc warning 2")
<< QString::fromLatin1("c:\\code\\test.h(96): Warning: Property declaration ) has no READ accessor function. The property will be invalid.")
@@ -155,7 +162,7 @@ void QtSupportPlugin::testQtOutputParser_data()
<< QString() << QString()
<< (Tasks() << CompileTask(Task::Unknown,
QLatin1String("No relevant classes found. No output generated."),
- Utils::FilePath::fromUserInput(QLatin1String("/home/qtwebkithelpviewer.h")), 0))
+ Utils::FilePath::fromUserInput(QLatin1String("/home/qtwebkithelpviewer.h")), -1))
<< QString();
QTest::newRow("ninja with moc")
<< QString::fromLatin1("E:/sandbox/creator/loaden/src/libs/utils/iwelcomepage.h(54): Error: Undefined interface")
@@ -188,4 +195,8 @@ void QtSupportPlugin::testQtOutputParser()
testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines, outputLines);
}
+
+} // namespace Internal
#endif
+
+} // namespace QtSupport
diff --git a/src/plugins/qtsupport/qtparser.h b/src/plugins/qtsupport/qtparser.h
index 5f891a2cf3..e70661f648 100644
--- a/src/plugins/qtsupport/qtparser.h
+++ b/src/plugins/qtsupport/qtparser.h
@@ -42,10 +42,10 @@ public:
QtParser();
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
QRegExp m_mocRegExp;
QRegExp m_translationRegExp;
};
-} // namespace ProjectExplorer
+} // namespace QtSupport
diff --git a/src/plugins/qtsupport/qttestparser.cpp b/src/plugins/qtsupport/qttestparser.cpp
index cf75303658..1e8a572f4a 100644
--- a/src/plugins/qtsupport/qttestparser.cpp
+++ b/src/plugins/qtsupport/qttestparser.cpp
@@ -47,7 +47,7 @@ using namespace Utils;
namespace QtSupport {
namespace Internal {
-OutputTaskParser::Status QtTestParser::handleLine(const QString &line, OutputFormat type)
+OutputLineParser::Result QtTestParser::handleLine(const QString &line, OutputFormat type)
{
if (type != StdOutFormat)
return Status::NotHandled;
@@ -69,11 +69,14 @@ OutputTaskParser::Status QtTestParser::handleLine(const QString &line, OutputFor
QTC_CHECK(locationPattern.isValid());
const QRegularExpressionMatch match = locationPattern.match(theLine);
if (match.hasMatch()) {
+ LinkSpecs linkSpecs;
m_currentTask.file = absoluteFilePath(FilePath::fromString(
QDir::fromNativeSeparators(match.captured("file"))));
m_currentTask.line = match.captured("line").toInt();
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_currentTask.file, m_currentTask.line, match,
+ "file");
emitCurrentTask();
- return Status::Done;
+ return {Status::Done, linkSpecs};
}
m_currentTask.description.append('\n').append(theLine);
return Status::InProgress;
@@ -82,7 +85,7 @@ OutputTaskParser::Status QtTestParser::handleLine(const QString &line, OutputFor
void QtTestParser::emitCurrentTask()
{
if (!m_currentTask.isNull()) {
- emit addTask(m_currentTask);
+ scheduleTask(m_currentTask, 1);
m_currentTask.clear();
}
}
diff --git a/src/plugins/qtsupport/qttestparser.h b/src/plugins/qtsupport/qttestparser.h
index 2ed4e78bf9..8e76eaba40 100644
--- a/src/plugins/qtsupport/qttestparser.h
+++ b/src/plugins/qtsupport/qttestparser.h
@@ -35,7 +35,7 @@ class QtTestParser : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
private:
- Status handleLine(const QString &line, Utils::OutputFormat type) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
void flush() override { emitCurrentTask(); }
void emitCurrentTask();
diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp
index 6a552296d1..7d24e38fb6 100644
--- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp
+++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp
@@ -139,15 +139,15 @@ void AbstractRemoteLinuxDeployStep::handleProgressMessage(const QString &message
void AbstractRemoteLinuxDeployStep::handleErrorMessage(const QString &message)
{
- emit addTask(DeploymentTask(Task::Error, message), 1); // TODO correct?
emit addOutput(message, OutputFormat::ErrorMessage);
+ emit addTask(DeploymentTask(Task::Error, message), 1); // TODO correct?
d->hasError = true;
}
void AbstractRemoteLinuxDeployStep::handleWarningMessage(const QString &message)
{
- emit addTask(DeploymentTask(Task::Warning, message), 1); // TODO correct?
emit addOutput(message, OutputFormat::ErrorMessage);
+ emit addTask(DeploymentTask(Task::Warning, message), 1); // TODO correct?
}
void AbstractRemoteLinuxDeployStep::handleFinished()
diff --git a/src/plugins/vcsbase/vcsoutputformatter.h b/src/plugins/vcsbase/vcsoutputformatter.h
index e4ebfc6fee..0b9486e2a9 100644
--- a/src/plugins/vcsbase/vcsoutputformatter.h
+++ b/src/plugins/vcsbase/vcsoutputformatter.h
@@ -31,7 +31,7 @@ QT_FORWARD_DECLARE_CLASS(QMenu)
namespace VcsBase {
-class VcsOutputLineParser : public QObject, public Utils::OutputLineParser
+class VcsOutputLineParser : public Utils::OutputLineParser
{
Q_OBJECT
public:
diff --git a/src/plugins/winrt/winrtpackagedeploymentstep.cpp b/src/plugins/winrt/winrtpackagedeploymentstep.cpp
index 32a474775b..5c2759672a 100644
--- a/src/plugins/winrt/winrtpackagedeploymentstep.cpp
+++ b/src/plugins/winrt/winrtpackagedeploymentstep.cpp
@@ -347,14 +347,14 @@ QString WinRtPackageDeploymentStep::defaultWinDeployQtArguments() const
void WinRtPackageDeploymentStep::raiseError(const QString &errorMessage)
{
- emit addTask(DeploymentTask(Task::Error, errorMessage), 1);
emit addOutput(errorMessage, BuildStep::OutputFormat::ErrorMessage);
+ emit addTask(DeploymentTask(Task::Error, errorMessage), 1);
}
void WinRtPackageDeploymentStep::raiseWarning(const QString &warningMessage)
{
- emit addTask(DeploymentTask(Task::Warning, warningMessage), 1);
emit addOutput(warningMessage, BuildStep::OutputFormat::NormalMessage);
+ emit addTask(DeploymentTask(Task::Warning, warningMessage), 1);
}
bool WinRtPackageDeploymentStep::parseIconsAndExecutableFromManifest(QString manifestFileName, QStringList *icons, QString *executable)