forked from qt-creator/qt-creator
Output parsers: Generalize the search directory concept
All parsers can now have search directories, not just the GnuMakeParser. This allows us to get rid of the "task mangling", removing another instance where the order of parsers in the chain mattered. Task-number: QTCREATORBUG-22665 Change-Id: Id0d55522ae6800afd9f50ff36546224b0d8bb382 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -115,7 +115,7 @@ bool AndroidPackageInstallationStep::init()
|
||||
IOutputParser *parser = target()->kit()->createOutputParser();
|
||||
if (parser)
|
||||
appendOutputParser(parser);
|
||||
outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
|
||||
outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
|
||||
|
||||
m_androidDirsToClean.clear();
|
||||
// don't remove gradle's cache, it takes ages to rebuild it.
|
||||
|
@@ -86,7 +86,7 @@ void JavaParser::parse(const QString &line)
|
||||
|
||||
CompileTask task(Task::Error,
|
||||
m_javaRegExp.cap(4).trimmed(),
|
||||
file /* filename */,
|
||||
absoluteFilePath(file),
|
||||
lineno);
|
||||
emit addTask(task, 1);
|
||||
return;
|
||||
|
@@ -158,7 +158,7 @@ bool IarParser::parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &ln
|
||||
const int lineno = match.captured(LineNumberIndex).toInt();
|
||||
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
|
||||
// A full description will be received later on next lines.
|
||||
newTask(CompileTask(type, {}, fileName, lineno));
|
||||
newTask(CompileTask(type, {}, absoluteFilePath(fileName), lineno));
|
||||
const QString firstPart = QString("[%1]: ").arg(match.captured(MessageCodeIndex));
|
||||
m_descriptionParts.append(firstPart);
|
||||
m_expectDescription = true;
|
||||
|
@@ -106,7 +106,7 @@ bool KeilParser::parseArmWarningOrErrorDetailsMessage(const QString &lne)
|
||||
const int lineno = match.captured(LineNumberIndex).toInt();
|
||||
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
|
||||
const QString descr = match.captured(DescriptionIndex);
|
||||
newTask(CompileTask(type, descr, fileName, lineno));
|
||||
newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ bool KeilParser::parseMcs51WarningOrErrorDetailsMessage1(const QString &lne)
|
||||
match.captured(FilePathIndex));
|
||||
const QString descr = QString("%1: %2").arg(match.captured(MessageCodeIndex),
|
||||
match.captured(MessageTextIndex));
|
||||
newTask(CompileTask(type, descr, fileName, lineno));
|
||||
newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ bool KeilParser::parseMcs51WarningOrErrorDetailsMessage2(const QString &lne)
|
||||
match.captured(FilePathIndex));
|
||||
const QString descr = QString("%1: %2").arg(match.captured(MessageCodeIndex),
|
||||
match.captured(MessageTextIndex));
|
||||
newTask(CompileTask(type, descr, fileName, lineno));
|
||||
newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -106,7 +106,7 @@ void SdccParser::stdError(const QString &line)
|
||||
const int lineno = match.captured(LineNumberIndex).toInt();
|
||||
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
|
||||
const QString descr = match.captured(MessageTextIndex);
|
||||
newTask(CompileTask(type, descr, fileName, lineno));
|
||||
newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ void SdccParser::stdError(const QString &line)
|
||||
const int lineno = match.captured(LineNumberIndex).toInt();
|
||||
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
|
||||
const QString descr = match.captured(MessageTextIndex);
|
||||
newTask(CompileTask(type, descr, fileName, lineno));
|
||||
newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -217,7 +217,7 @@ bool CMakeBuildStep::init()
|
||||
IOutputParser *parser = target()->kit()->createOutputParser();
|
||||
if (parser)
|
||||
appendOutputParser(parser);
|
||||
outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
|
||||
outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
|
||||
|
||||
return AbstractProcessStep::init();
|
||||
}
|
||||
|
@@ -80,13 +80,13 @@ void CMakeParser::stdError(const QString &line)
|
||||
|
||||
m_lastTask = BuildSystemTask(Task::Error,
|
||||
QString(),
|
||||
FilePath::fromUserInput(path),
|
||||
absoluteFilePath(FilePath::fromUserInput(path)),
|
||||
m_commonError.cap(2).toInt());
|
||||
m_lines = 1;
|
||||
return;
|
||||
} else if (m_nextSubError.indexIn(trimmedLine) != -1) {
|
||||
m_lastTask = BuildSystemTask(Task::Error, QString(),
|
||||
FilePath::fromUserInput(m_nextSubError.cap(1)));
|
||||
absoluteFilePath(FilePath::fromUserInput(m_nextSubError.cap(1))));
|
||||
m_lines = 1;
|
||||
return;
|
||||
} else if (trimmedLine.startsWith(QLatin1String(" ")) && !m_lastTask.isNull()) {
|
||||
|
@@ -226,7 +226,7 @@ bool IosBuildStep::init()
|
||||
IOutputParser *parser = target()->kit()->createOutputParser();
|
||||
if (parser)
|
||||
appendOutputParser(parser);
|
||||
outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
|
||||
outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
|
||||
|
||||
return AbstractProcessStep::init();
|
||||
}
|
||||
|
@@ -82,7 +82,7 @@ bool IosDsymBuildStep::init()
|
||||
|
||||
setOutputParser(target()->kit()->createOutputParser());
|
||||
if (outputParser())
|
||||
outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
|
||||
outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
|
||||
|
||||
return AbstractProcessStep::init();
|
||||
}
|
||||
|
@@ -87,7 +87,8 @@ private:
|
||||
else
|
||||
return;
|
||||
|
||||
emit addTask(CompileTask(type, message, FilePath::fromUserInput(filename), lineNumber));
|
||||
emit addTask(CompileTask(type, message, absoluteFilePath(FilePath::fromUserInput(filename)),
|
||||
lineNumber));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -107,7 +108,7 @@ NimbleBuildStep::NimbleBuildStep(BuildStepList *parentList, Core::Id id)
|
||||
bool NimbleBuildStep::init()
|
||||
{
|
||||
auto parser = new NimParser();
|
||||
parser->setWorkingDirectory(project()->projectDirectory());
|
||||
parser->addSearchDir(project()->projectDirectory());
|
||||
setOutputParser(parser);
|
||||
|
||||
ProcessParameters* params = processParameters();
|
||||
|
@@ -89,7 +89,8 @@ private:
|
||||
else
|
||||
return;
|
||||
|
||||
emit addTask(CompileTask(type, message, FilePath::fromUserInput(filename), lineNumber));
|
||||
emit addTask(CompileTask(type, message, absoluteFilePath(FilePath::fromUserInput(filename)),
|
||||
lineNumber));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -116,7 +117,7 @@ bool NimCompilerBuildStep::init()
|
||||
setOutputParser(new NimParser());
|
||||
if (IOutputParser *parser = target()->kit()->createOutputParser())
|
||||
appendOutputParser(parser);
|
||||
outputParser()->setWorkingDirectory(processParameters()->effectiveWorkingDirectory());
|
||||
outputParser()->addSearchDir(processParameters()->effectiveWorkingDirectory());
|
||||
return AbstractProcessStep::init();
|
||||
}
|
||||
|
||||
|
@@ -76,7 +76,7 @@ void ClangParser::stdError(const QString &line)
|
||||
m_expectSnippet = true;
|
||||
newTask(CompileTask(Task::Unknown,
|
||||
lne.trimmed(),
|
||||
FilePath::fromUserInput(match.captured(2)), /* filename */
|
||||
absoluteFilePath(FilePath::fromUserInput(match.captured(2))),
|
||||
match.captured(3).toInt() /* line */));
|
||||
return;
|
||||
}
|
||||
@@ -90,7 +90,7 @@ void ClangParser::stdError(const QString &line)
|
||||
lineNo = match.captured(5).toInt(&ok);
|
||||
newTask(CompileTask(taskType(match.captured(7)),
|
||||
match.captured(8),
|
||||
FilePath::fromUserInput(match.captured(1)), /* filename */
|
||||
absoluteFilePath(FilePath::fromUserInput(match.captured(1))),
|
||||
lineNo));
|
||||
return;
|
||||
}
|
||||
|
@@ -145,13 +145,6 @@ Core::Id CustomParser::id()
|
||||
return Core::Id("ProjectExplorer.OutputParser.Custom");
|
||||
}
|
||||
|
||||
FilePath CustomParser::absoluteFilePath(const QString &filePath) const
|
||||
{
|
||||
if (workingDirectory().isEmpty())
|
||||
return FilePath::fromUserInput(filePath);
|
||||
return workingDirectory().resolvePath(filePath);
|
||||
}
|
||||
|
||||
bool CustomParser::hasMatch(const QString &line, CustomParserExpression::CustomParserChannel channel,
|
||||
const CustomParserExpression &expression, Task::TaskType taskType)
|
||||
{
|
||||
@@ -165,7 +158,8 @@ bool CustomParser::hasMatch(const QString &line, CustomParserExpression::CustomP
|
||||
if (!match.hasMatch())
|
||||
return false;
|
||||
|
||||
const FilePath fileName = absoluteFilePath(match.captured(expression.fileNameCap()));
|
||||
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());
|
||||
|
||||
@@ -475,7 +469,8 @@ void ProjectExplorerPlugin::testCustomOutputParsers()
|
||||
|
||||
CustomParser *parser = new CustomParser;
|
||||
parser->setSettings(settings);
|
||||
parser->setWorkingDirectory(FilePath::fromString(workDir));
|
||||
parser->addSearchDir(FilePath::fromString(workDir));
|
||||
parser->skipFileExistsCheck();
|
||||
|
||||
OutputParserTester testbench;
|
||||
testbench.appendOutputParser(parser);
|
||||
|
@@ -94,7 +94,6 @@ public:
|
||||
static Core::Id id();
|
||||
|
||||
private:
|
||||
Utils::FilePath absoluteFilePath(const QString &filePath) const;
|
||||
bool hasMatch(const QString &line, CustomParserExpression::CustomParserChannel channel,
|
||||
const CustomParserExpression &expression, Task::TaskType taskType);
|
||||
bool parseLine(const QString &rawLine, CustomParserExpression::CustomParserChannel channel);
|
||||
|
@@ -113,7 +113,7 @@ void GccParser::stdError(const QString &line)
|
||||
if (match.captured(5).startsWith(QLatin1Char('#')))
|
||||
description = match.captured(5) + description;
|
||||
|
||||
newTask(CompileTask(type, description, filename, lineno));
|
||||
newTask(CompileTask(type, description, absoluteFilePath(filename), lineno));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ void GccParser::stdError(const QString &line)
|
||||
if (match.hasMatch()) {
|
||||
newTask(CompileTask(Task::Unknown,
|
||||
lne.trimmed() /* description */,
|
||||
Utils::FilePath::fromUserInput(match.captured(1)) /* filename */,
|
||||
absoluteFilePath(Utils::FilePath::fromUserInput(match.captured(1))),
|
||||
match.captured(3).toInt() /* linenumber */));
|
||||
return;
|
||||
} else if (lne.startsWith(' ') && !m_currentTask.isNull()) {
|
||||
|
@@ -29,7 +29,7 @@
|
||||
#include "task.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/temporarydirectory.h>
|
||||
#include <utils/temporaryfile.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
@@ -68,9 +68,9 @@ void GnuMakeParser::stdOutput(const QString &line)
|
||||
QRegularExpressionMatch match = m_makeDir.match(lne);
|
||||
if (match.hasMatch()) {
|
||||
if (match.captured(6) == QLatin1String("Leaving"))
|
||||
removeDirectory(match.captured(7));
|
||||
dropSearchDir(FilePath::fromString(match.captured(7)));
|
||||
else
|
||||
addDirectory(match.captured(7));
|
||||
addSearchDir(FilePath::fromString(match.captured(7)));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,10 +128,9 @@ void GnuMakeParser::stdError(const QString &line)
|
||||
if (res.isFatal)
|
||||
++m_fatalErrorCount;
|
||||
if (!m_suppressIssues) {
|
||||
taskAdded(BuildSystemTask(res.type, res.description,
|
||||
FilePath::fromUserInput(match.captured(1)) /* filename */,
|
||||
match.captured(4).toInt() /* line */),
|
||||
1, 0);
|
||||
emitTask(BuildSystemTask(res.type, res.description,
|
||||
absoluteFilePath(FilePath::fromUserInput(match.captured(1))),
|
||||
match.captured(4).toInt() /* line */));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -142,61 +141,18 @@ void GnuMakeParser::stdError(const QString &line)
|
||||
if (res.isFatal)
|
||||
++m_fatalErrorCount;
|
||||
if (!m_suppressIssues)
|
||||
taskAdded(BuildSystemTask(res.type, res.description), 1, 0);
|
||||
emitTask(BuildSystemTask(res.type, res.description));
|
||||
return;
|
||||
}
|
||||
|
||||
IOutputParser::stdError(line);
|
||||
}
|
||||
|
||||
void GnuMakeParser::addDirectory(const QString &dir)
|
||||
void GnuMakeParser::emitTask(const ProjectExplorer::Task &task)
|
||||
{
|
||||
if (dir.isEmpty())
|
||||
return;
|
||||
m_directories.append(dir);
|
||||
}
|
||||
|
||||
void GnuMakeParser::removeDirectory(const QString &dir)
|
||||
{
|
||||
m_directories.removeOne(dir);
|
||||
}
|
||||
|
||||
void GnuMakeParser::taskAdded(const Task &task, int linkedLines, int skippedLines)
|
||||
{
|
||||
Task editable(task);
|
||||
|
||||
if (task.type == Task::Error) {
|
||||
// assume that all make errors will be follow up errors:
|
||||
if (task.type == Task::Error) // Assume that all make errors will be follow up errors.
|
||||
m_suppressIssues = true;
|
||||
}
|
||||
|
||||
QString filePath(task.file.toString());
|
||||
|
||||
if (!filePath.isEmpty() && !QDir::isAbsolutePath(filePath)) {
|
||||
QFileInfoList possibleFiles;
|
||||
foreach (const QString &dir, searchDirectories()) {
|
||||
QFileInfo candidate(dir + QLatin1Char('/') + filePath);
|
||||
if (candidate.exists()
|
||||
&& !possibleFiles.contains(candidate)) {
|
||||
possibleFiles << candidate;
|
||||
}
|
||||
}
|
||||
if (possibleFiles.size() == 1)
|
||||
editable.file = Utils::FilePath::fromFileInfo(possibleFiles.first());
|
||||
// Let the Makestep apply additional heuristics (based on
|
||||
// files in ther project) if we cannot uniquely
|
||||
// identify the file!
|
||||
}
|
||||
|
||||
IOutputParser::taskAdded(editable, linkedLines, skippedLines);
|
||||
}
|
||||
|
||||
QStringList GnuMakeParser::searchDirectories() const
|
||||
{
|
||||
QStringList dirs = m_directories;
|
||||
if (!workingDirectory().isEmpty())
|
||||
dirs << workingDirectory().toString();
|
||||
return dirs;
|
||||
emit addTask(task, 1, 0);
|
||||
}
|
||||
|
||||
} // ProjectExplorer
|
||||
@@ -417,117 +373,52 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing()
|
||||
QFETCH(QString, outputLines);
|
||||
QFETCH(QStringList, additionalSearchDirs);
|
||||
|
||||
QStringList searchDirs = childParser->searchDirectories();
|
||||
FilePaths searchDirs = childParser->searchDirectories();
|
||||
|
||||
// add extra directories:
|
||||
foreach (const QString &dir, extraSearchDirs)
|
||||
childParser->addDirectory(dir);
|
||||
childParser->addSearchDir(FilePath::fromString(dir));
|
||||
|
||||
testbench.testParsing(input, inputChannel,
|
||||
tasks, childStdOutLines, childStdErrLines,
|
||||
outputLines);
|
||||
|
||||
// make sure we still have all the original dirs
|
||||
QStringList newSearchDirs = tester->directories;
|
||||
foreach (const QString &dir, searchDirs) {
|
||||
FilePaths newSearchDirs = tester->directories;
|
||||
foreach (const FilePath &dir, searchDirs) {
|
||||
QVERIFY(newSearchDirs.contains(dir));
|
||||
newSearchDirs.removeOne(dir);
|
||||
}
|
||||
|
||||
// make sure we have all additional dirs:
|
||||
foreach (const QString &dir, additionalSearchDirs) {
|
||||
QVERIFY(newSearchDirs.contains(dir));
|
||||
newSearchDirs.removeOne(dir);
|
||||
const FilePath fp = FilePath::fromString(dir);
|
||||
QVERIFY(newSearchDirs.contains(fp));
|
||||
newSearchDirs.removeOne(fp);
|
||||
}
|
||||
// make sure we have no extra cruft:
|
||||
QVERIFY(newSearchDirs.isEmpty());
|
||||
delete tester;
|
||||
}
|
||||
|
||||
void ProjectExplorerPlugin::testGnuMakeParserTaskMangling_data()
|
||||
{
|
||||
QTest::addColumn<QStringList>("files");
|
||||
QTest::addColumn<QStringList>("searchDirectories");
|
||||
QTest::addColumn<Task>("inputTask");
|
||||
QTest::addColumn<Task>("outputTask");
|
||||
|
||||
QTest::newRow("no filename")
|
||||
<< QStringList()
|
||||
<< QStringList()
|
||||
<< Task(CompileTask(Task::Error,
|
||||
"no filename, no mangling"))
|
||||
<< Task(CompileTask(Task::Error,
|
||||
"no filename, no mangling"));
|
||||
|
||||
QTest::newRow("no mangling")
|
||||
<< QStringList()
|
||||
<< QStringList()
|
||||
<< Task(CompileTask(Task::Error,
|
||||
"unknown filename, no mangling",
|
||||
FilePath::fromUserInput("some/path/unknown.cpp")))
|
||||
<< Task(CompileTask(Task::Error,
|
||||
"unknown filename, no mangling",
|
||||
FilePath::fromUserInput("some/path/unknown.cpp")));
|
||||
|
||||
QTest::newRow("find file")
|
||||
<< QStringList("test/file.cpp")
|
||||
<< QStringList("test")
|
||||
<< Task(CompileTask(Task::Error,
|
||||
"mangling",
|
||||
FilePath::fromUserInput("file.cpp"),
|
||||
10))
|
||||
<< Task(CompileTask(Task::Error,
|
||||
"mangling",
|
||||
FilePath::fromUserInput("$TMPDIR/test/file.cpp"),
|
||||
10));
|
||||
}
|
||||
|
||||
void ProjectExplorerPlugin::testGnuMakeParserTaskMangling()
|
||||
{
|
||||
TemporaryFile theMakeFile("Makefile.XXXXXX");
|
||||
QVERIFY2(theMakeFile.open(), qPrintable(theMakeFile.errorString()));
|
||||
QFileInfo fi(theMakeFile);
|
||||
QVERIFY2(fi.fileName().startsWith("Makefile"), qPrintable(theMakeFile.fileName()));
|
||||
|
||||
OutputParserTester testbench;
|
||||
auto *childParser = new GnuMakeParser;
|
||||
testbench.appendOutputParser(childParser);
|
||||
|
||||
QFETCH(QStringList, files);
|
||||
QFETCH(QStringList, searchDirectories);
|
||||
QFETCH(Task, inputTask);
|
||||
QFETCH(Task, outputTask);
|
||||
|
||||
// setup files:
|
||||
const QString tempdir
|
||||
= Utils::TemporaryDirectory::masterDirectoryPath() + '/' + QUuid::createUuid().toString() + '/';
|
||||
QDir filedir(tempdir);
|
||||
foreach (const QString &file, files) {
|
||||
Q_ASSERT(!file.startsWith('/'));
|
||||
Q_ASSERT(!file.contains("../"));
|
||||
|
||||
filedir.mkpath(file.left(file.lastIndexOf('/')));
|
||||
|
||||
QFile tempfile(tempdir + file);
|
||||
if (!tempfile.open(QIODevice::WriteOnly))
|
||||
continue;
|
||||
tempfile.write("Delete me again!");
|
||||
tempfile.close();
|
||||
}
|
||||
|
||||
// setup search dirs:
|
||||
foreach (const QString &dir, searchDirectories) {
|
||||
Q_ASSERT(!dir.startsWith(QLatin1Char('/')));
|
||||
Q_ASSERT(!dir.contains(QLatin1String("../")));
|
||||
childParser->addDirectory(tempdir + dir);
|
||||
}
|
||||
|
||||
// fix up output task file:
|
||||
QString filePath = outputTask.file.toString();
|
||||
if (filePath.startsWith(QLatin1String("$TMPDIR/")))
|
||||
outputTask.file = Utils::FilePath::fromString(filePath.replace(QLatin1String("$TMPDIR/"), tempdir));
|
||||
|
||||
// test mangling:
|
||||
testbench.testTaskMangling(inputTask, outputTask);
|
||||
|
||||
// clean up:
|
||||
foreach (const QString &file, files)
|
||||
filedir.rmpath(tempdir + file);
|
||||
childParser->addSearchDir(FilePath::fromString(fi.absolutePath()));
|
||||
testbench.testParsing(
|
||||
fi.fileName() + ":360: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.",
|
||||
OutputParserTester::STDERR,
|
||||
{BuildSystemTask(Task::Error,
|
||||
"missing separator (did you mean TAB instead of 8 spaces?). Stop.",
|
||||
FilePath::fromString(theMakeFile.fileName()), 360)},
|
||||
QString(), QString(), QString());
|
||||
}
|
||||
|
||||
} // ProjectExplorer
|
||||
|
@@ -42,23 +42,16 @@ public:
|
||||
void stdOutput(const QString &line) override;
|
||||
void stdError(const QString &line) override;
|
||||
|
||||
QStringList searchDirectories() const;
|
||||
|
||||
bool hasFatalErrors() const override;
|
||||
|
||||
void taskAdded(const ProjectExplorer::Task &task, int linkedLines, int skippedLines) override;
|
||||
|
||||
private:
|
||||
void addDirectory(const QString &dir);
|
||||
void removeDirectory(const QString &dir);
|
||||
void emitTask(const ProjectExplorer::Task &task);
|
||||
|
||||
QRegularExpression m_makeDir;
|
||||
QRegularExpression m_makeLine;
|
||||
QRegularExpression m_threeStarError;
|
||||
QRegularExpression m_errorInMakefile;
|
||||
|
||||
QStringList m_directories;
|
||||
|
||||
bool m_suppressIssues = false;
|
||||
|
||||
int m_fatalErrorCount = 0;
|
||||
@@ -77,7 +70,7 @@ public:
|
||||
explicit GnuMakeParserTester(GnuMakeParser *parser, QObject *parent = nullptr);
|
||||
void parserIsAboutToBeDeleted();
|
||||
|
||||
QStringList directories;
|
||||
Utils::FilePaths directories;
|
||||
GnuMakeParser *parser;
|
||||
};
|
||||
#endif
|
||||
|
@@ -28,6 +28,9 @@
|
||||
|
||||
#include <utils/synchronousprocess.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
|
||||
/*!
|
||||
\class ProjectExplorer::IOutputParser
|
||||
|
||||
@@ -162,9 +165,10 @@ public:
|
||||
|
||||
IOutputParser *childParser = nullptr;
|
||||
QList<Filter> filters;
|
||||
Utils::FilePath workingDir;
|
||||
Utils::FilePaths searchDirs;
|
||||
OutputChannelState stdoutState;
|
||||
OutputChannelState stderrState;
|
||||
bool skipFileExistsCheck = false;
|
||||
};
|
||||
|
||||
IOutputParser::IOutputParser() : d(new IOutputParserPrivate(this))
|
||||
@@ -197,7 +201,7 @@ void IOutputParser::appendOutputParser(IOutputParser *parser)
|
||||
}
|
||||
|
||||
d->childParser = parser;
|
||||
connect(parser, &IOutputParser::addTask, this, &IOutputParser::taskAdded);
|
||||
connect(parser, &IOutputParser::addTask, this, &IOutputParser::addTask);
|
||||
}
|
||||
|
||||
IOutputParser *IOutputParser::childParser() const
|
||||
@@ -211,7 +215,7 @@ void IOutputParser::setChildParser(IOutputParser *parser)
|
||||
delete d->childParser;
|
||||
d->childParser = parser;
|
||||
if (parser)
|
||||
connect(parser, &IOutputParser::addTask, this, &IOutputParser::taskAdded);
|
||||
connect(parser, &IOutputParser::addTask, this, &IOutputParser::addTask);
|
||||
}
|
||||
|
||||
void IOutputParser::stdOutput(const QString &line)
|
||||
@@ -226,28 +230,18 @@ void IOutputParser::stdError(const QString &line)
|
||||
d->childParser->stdError(line);
|
||||
}
|
||||
|
||||
Utils::FilePath IOutputParser::workingDirectory() const { return d->workingDir; }
|
||||
|
||||
void IOutputParser::taskAdded(const Task &task, int linkedOutputLines, int skipLines)
|
||||
void IOutputParser::skipFileExistsCheck()
|
||||
{
|
||||
emit addTask(task, linkedOutputLines, skipLines);
|
||||
d->skipFileExistsCheck = true;
|
||||
}
|
||||
|
||||
void IOutputParser::doFlush()
|
||||
{ }
|
||||
void IOutputParser::doFlush() { }
|
||||
|
||||
bool IOutputParser::hasFatalErrors() const
|
||||
{
|
||||
return d->childParser && d->childParser->hasFatalErrors();
|
||||
}
|
||||
|
||||
void IOutputParser::setWorkingDirectory(const Utils::FilePath &fn)
|
||||
{
|
||||
d->workingDir = fn;
|
||||
if (d->childParser)
|
||||
d->childParser->setWorkingDirectory(fn);
|
||||
}
|
||||
|
||||
void IOutputParser::flush()
|
||||
{
|
||||
flushTasks();
|
||||
@@ -278,4 +272,40 @@ void IOutputParser::addFilter(const Filter &filter)
|
||||
d->filters << filter;
|
||||
}
|
||||
|
||||
void IOutputParser::addSearchDir(const Utils::FilePath &dir)
|
||||
{
|
||||
d->searchDirs << dir;
|
||||
if (d->childParser)
|
||||
d->childParser->addSearchDir(dir);
|
||||
}
|
||||
|
||||
void IOutputParser::dropSearchDir(const Utils::FilePath &dir)
|
||||
{
|
||||
const int idx = d->searchDirs.lastIndexOf(dir);
|
||||
QTC_ASSERT(idx != -1, return);
|
||||
d->searchDirs.removeAt(idx);
|
||||
if (d->childParser)
|
||||
d->childParser->dropSearchDir(dir);
|
||||
}
|
||||
|
||||
const Utils::FilePaths IOutputParser::searchDirectories() const
|
||||
{
|
||||
return d->searchDirs;
|
||||
}
|
||||
|
||||
Utils::FilePath IOutputParser::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()));
|
||||
return filePath;
|
||||
}
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
@@ -56,15 +56,16 @@ public:
|
||||
using Filter = std::function<QString(const QString &)>;
|
||||
void addFilter(const Filter &filter);
|
||||
|
||||
void setWorkingDirectory(const Utils::FilePath &fn);
|
||||
void addSearchDir(const Utils::FilePath &dir);
|
||||
void dropSearchDir(const Utils::FilePath &dir);
|
||||
const Utils::FilePaths searchDirectories() const;
|
||||
void skipFileExistsCheck(); // For testing only
|
||||
|
||||
void flush(); // flush pending tasks & output
|
||||
void flushTasks(); // flush pending tasks only
|
||||
|
||||
static QString rightTrimmed(const QString &in);
|
||||
|
||||
virtual void taskAdded(const ProjectExplorer::Task &task, int linkedOutputLines = 0, int skipLines = 0);
|
||||
|
||||
signals:
|
||||
void addTask(const ProjectExplorer::Task &task, int linkedOutputLines = 0, int skipLines = 0);
|
||||
|
||||
@@ -72,7 +73,7 @@ protected:
|
||||
virtual void stdOutput(const QString &line);
|
||||
virtual void stdError(const QString &line);
|
||||
|
||||
Utils::FilePath workingDirectory() const;
|
||||
Utils::FilePath absoluteFilePath(const Utils::FilePath &filePath);
|
||||
|
||||
private:
|
||||
virtual void doFlush();
|
||||
|
@@ -133,7 +133,7 @@ void LdParser::stdError(const QString &line)
|
||||
type = Task::Warning;
|
||||
description = description.mid(9);
|
||||
}
|
||||
emit addTask(CompileTask(type, description, filename, lineno), 1);
|
||||
emit addTask(CompileTask(type, description, absoluteFilePath(filename), lineno), 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -85,7 +85,7 @@ void LinuxIccParser::stdError(const QString &line)
|
||||
type = Task::Warning;
|
||||
m_temporary = CompileTask(type,
|
||||
m_firstLine.cap(6).trimmed(),
|
||||
Utils::FilePath::fromUserInput(m_firstLine.cap(1)),
|
||||
absoluteFilePath(Utils::FilePath::fromUserInput(m_firstLine.cap(1))),
|
||||
m_firstLine.cap(2).toInt());
|
||||
|
||||
m_lines = 1;
|
||||
|
@@ -64,7 +64,8 @@ void LldParser::stdError(const QString &line)
|
||||
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(), file, lineNo));
|
||||
emit addTask(CompileTask(Task::Unknown, trimmedLine.mid(4).trimmed(),
|
||||
absoluteFilePath(file), lineNo));
|
||||
return;
|
||||
}
|
||||
IOutputParser::stdError(line);
|
||||
|
@@ -106,7 +106,7 @@ bool MakeStep::init()
|
||||
IOutputParser *parser = target()->kit()->createOutputParser();
|
||||
if (parser)
|
||||
appendOutputParser(parser);
|
||||
outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
|
||||
outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
|
||||
|
||||
return AbstractProcessStep::init();
|
||||
}
|
||||
|
@@ -142,7 +142,7 @@ void MsvcParser::stdOutput(const QString &line)
|
||||
if (!match.captured(1).isEmpty())
|
||||
description.chop(1); // Remove trailing quote
|
||||
m_lastTask = CompileTask(Task::Unknown, description,
|
||||
FilePath::fromUserInput(match.captured(2)), /* fileName */
|
||||
absoluteFilePath(FilePath::fromUserInput(match.captured(2))),
|
||||
match.captured(3).toInt() /* linenumber */);
|
||||
m_lines = 1;
|
||||
return;
|
||||
@@ -176,7 +176,7 @@ bool MsvcParser::processCompileLine(const QString &line)
|
||||
QPair<FilePath, int> position = parseFileName(match.captured(1));
|
||||
m_lastTask = CompileTask(taskType(match.captured(2)),
|
||||
match.captured(3) + match.captured(4).trimmed(), // description
|
||||
position.first, position.second);
|
||||
absoluteFilePath(position.first), position.second);
|
||||
m_lines = 1;
|
||||
return true;
|
||||
}
|
||||
@@ -257,7 +257,7 @@ void ClangClParser::stdError(const QString &lineIn)
|
||||
doFlush();
|
||||
const QPair<FilePath, int> position = parseFileName(match.captured(1));
|
||||
m_lastTask = CompileTask(taskType(match.captured(2)), match.captured(3).trimmed(),
|
||||
position.first, position.second);
|
||||
absoluteFilePath(position.first), position.second);
|
||||
m_linkedLines = 1;
|
||||
return;
|
||||
}
|
||||
|
@@ -39,6 +39,13 @@ static inline QByteArray msgFileComparisonFail(const Utils::FilePath &f1, const
|
||||
}
|
||||
|
||||
// test functions:
|
||||
OutputParserTester::OutputParserTester()
|
||||
{
|
||||
connect(this, &IOutputParser::addTask, this, [this](const Task &t) {
|
||||
m_receivedTasks.append(t);
|
||||
});
|
||||
}
|
||||
|
||||
void OutputParserTester::testParsing(const QString &lines,
|
||||
Channel inputChannel,
|
||||
Tasks tasks,
|
||||
@@ -79,38 +86,11 @@ void OutputParserTester::testParsing(const QString &lines,
|
||||
}
|
||||
}
|
||||
|
||||
void OutputParserTester::testTaskMangling(const Task &input,
|
||||
const Task &output)
|
||||
{
|
||||
reset();
|
||||
childParser()->taskAdded(input);
|
||||
|
||||
QVERIFY(m_receivedOutput.isNull());
|
||||
QVERIFY(m_receivedStdErrChildLine.isNull());
|
||||
QVERIFY(m_receivedStdOutChildLine.isNull());
|
||||
QVERIFY(m_receivedTasks.size() == 1);
|
||||
if (m_receivedTasks.size() == 1) {
|
||||
QCOMPARE(m_receivedTasks.at(0).category, output.category);
|
||||
QCOMPARE(m_receivedTasks.at(0).description, output.description);
|
||||
QVERIFY2(m_receivedTasks.at(0).file == output.file,
|
||||
msgFileComparisonFail(m_receivedTasks.at(0).file, output.file));
|
||||
QCOMPARE(m_receivedTasks.at(0).line, output.line);
|
||||
QCOMPARE(m_receivedTasks.at(0).type, output.type);
|
||||
}
|
||||
}
|
||||
|
||||
void OutputParserTester::setDebugEnabled(bool debug)
|
||||
{
|
||||
m_debug = debug;
|
||||
}
|
||||
|
||||
void OutputParserTester::taskAdded(const Task &task, int linkedLines, int skipLines)
|
||||
{
|
||||
Q_UNUSED(linkedLines)
|
||||
Q_UNUSED(skipLines)
|
||||
m_receivedTasks.append(task);
|
||||
}
|
||||
|
||||
void OutputParserTester::reset()
|
||||
{
|
||||
m_receivedStdErrChildLine.clear();
|
||||
|
@@ -46,14 +46,14 @@ public:
|
||||
STDERR
|
||||
};
|
||||
|
||||
OutputParserTester();
|
||||
|
||||
// test functions:
|
||||
void testParsing(const QString &lines, Channel inputChannel,
|
||||
Tasks tasks,
|
||||
const QString &childStdOutLines,
|
||||
const QString &childStdErrLines,
|
||||
const QString &outputLines);
|
||||
void testTaskMangling(const Task &input,
|
||||
const Task &output);
|
||||
|
||||
void setDebugEnabled(bool);
|
||||
|
||||
@@ -61,8 +61,6 @@ signals:
|
||||
void aboutToDeleteParser();
|
||||
|
||||
private:
|
||||
void taskAdded(const ProjectExplorer::Task &task, int linkedLines, int skipLines) override;
|
||||
|
||||
void reset();
|
||||
|
||||
bool m_debug = false;
|
||||
|
@@ -229,7 +229,6 @@ private slots:
|
||||
|
||||
void testGnuMakeParserParsing_data();
|
||||
void testGnuMakeParserParsing();
|
||||
void testGnuMakeParserTaskMangling_data();
|
||||
void testGnuMakeParserTaskMangling();
|
||||
|
||||
void testXcodebuildParserParsing_data();
|
||||
|
@@ -74,8 +74,8 @@ void XcodebuildParser::stdOutput(const QString &line)
|
||||
if (lne.endsWith(QLatin1String(signatureChangeEndsWithPattern))) {
|
||||
CompileTask task(Task::Warning,
|
||||
tr("Replacing signature"),
|
||||
FilePath::fromString(
|
||||
lne.left(lne.size() - QLatin1String(signatureChangeEndsWithPattern).size())));
|
||||
absoluteFilePath(FilePath::fromString(
|
||||
lne.left(lne.size() - QLatin1String(signatureChangeEndsWithPattern).size()))));
|
||||
emit addTask(task, 1);
|
||||
return;
|
||||
}
|
||||
|
@@ -376,7 +376,7 @@ void QbsBuildStep::handleProcessResult(
|
||||
return;
|
||||
|
||||
if (m_parser)
|
||||
m_parser->setWorkingDirectory(workingDir);
|
||||
m_parser->addSearchDir(workingDir);
|
||||
emit addOutput(executable.toUserOutput() + ' ' + QtcProcess::joinArgs(arguments),
|
||||
OutputFormat::Stdout);
|
||||
for (const QString &line : stdErr) {
|
||||
@@ -389,8 +389,10 @@ void QbsBuildStep::handleProcessResult(
|
||||
m_parser->handleStdout(line + '\n');
|
||||
emit addOutput(line, OutputFormat::Stdout);
|
||||
}
|
||||
if (m_parser)
|
||||
if (m_parser) {
|
||||
m_parser->flush();
|
||||
m_parser->dropSearchDir(workingDir);
|
||||
}
|
||||
}
|
||||
|
||||
void QbsBuildStep::createTaskAndOutput(ProjectExplorer::Task::TaskType type, const QString &message,
|
||||
|
@@ -171,7 +171,7 @@ bool QmakeMakeStep::init()
|
||||
IOutputParser *parser = target()->kit()->createOutputParser();
|
||||
if (parser)
|
||||
appendOutputParser(parser);
|
||||
outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
|
||||
outputParser()->addSearchDir(pp->effectiveWorkingDirectory());
|
||||
appendOutputParser(new QMakeParser); // make may cause qmake to be run, add last to make sure
|
||||
// it has a low priority.
|
||||
|
||||
|
@@ -61,7 +61,7 @@ void QMakeParser::stdError(const QString &line)
|
||||
type = Task::Error;
|
||||
emit addTask(BuildSystemTask(type,
|
||||
description,
|
||||
FilePath::fromUserInput(fileName),
|
||||
absoluteFilePath(FilePath::fromUserInput(fileName)),
|
||||
m_error.cap(2).toInt() /* line */),
|
||||
1);
|
||||
return;
|
||||
|
@@ -338,7 +338,7 @@ void QMakeStep::runNextCommand()
|
||||
case State::RUN_MAKE_QMAKE_ALL:
|
||||
{
|
||||
auto *parser = new GnuMakeParser;
|
||||
parser->setWorkingDirectory(processParameters()->workingDirectory());
|
||||
parser->addSearchDir(processParameters()->workingDirectory());
|
||||
setOutputParser(parser);
|
||||
m_nextState = State::POST_PROCESS;
|
||||
startOneCommand(m_makeCommand);
|
||||
|
@@ -58,7 +58,7 @@ void QtParser::stdError(const QString &line)
|
||||
if (level.compare(QLatin1String("Note"), Qt::CaseInsensitive) == 0)
|
||||
type = Task::Unknown;
|
||||
CompileTask task(type, m_mocRegExp.cap(5).trimmed() /* description */,
|
||||
Utils::FilePath::fromUserInput(m_mocRegExp.cap(1)) /* filename */,
|
||||
absoluteFilePath(Utils::FilePath::fromUserInput(m_mocRegExp.cap(1))),
|
||||
lineno);
|
||||
emit addTask(task, 1);
|
||||
return;
|
||||
@@ -68,7 +68,7 @@ void QtParser::stdError(const QString &line)
|
||||
if (m_translationRegExp.cap(1) == QLatin1String("Error"))
|
||||
type = Task::Error;
|
||||
CompileTask task(type, m_translationRegExp.cap(2),
|
||||
Utils::FilePath::fromUserInput(m_translationRegExp.cap(3)));
|
||||
absoluteFilePath(Utils::FilePath::fromUserInput(m_translationRegExp.cap(3))));
|
||||
emit addTask(task, 1);
|
||||
return;
|
||||
}
|
||||
|
@@ -68,8 +68,8 @@ void QtTestParser::stdOutput(const QString &line)
|
||||
QTC_CHECK(locationPattern.isValid());
|
||||
const QRegularExpressionMatch match = locationPattern.match(theLine);
|
||||
if (match.hasMatch()) {
|
||||
m_currentTask.file = FilePath::fromString(
|
||||
QDir::fromNativeSeparators(match.captured("file")));
|
||||
m_currentTask.file = absoluteFilePath(FilePath::fromString(
|
||||
QDir::fromNativeSeparators(match.captured("file"))));
|
||||
m_currentTask.line = match.captured("line").toInt();
|
||||
emitCurrentTask();
|
||||
return;
|
||||
|
Reference in New Issue
Block a user