forked from qt-creator/qt-creator
ProjectExplorer: Handle files with no line number in GCC output parser
This necessitated changes in the LdParser, as it turned out that a lot of linker messages were not actually caught there, but by accident in the GccParser (mostly by a now-superfluous regex). Note that the LdParser is still pretty awful; we just did the minimum that was necessary to keep the tests passing. Fixes: QTCREATORBUG-30806 Change-Id: I97ef08ca2bb8990841a95621f07368e879734856 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -342,6 +342,7 @@ OutputLineParser::Result OutputFormatter::handleMessage(const QString &text, Out
|
|||||||
= d->nextParser->handleLine(text, outputTypeForParser(d->nextParser, format));
|
= d->nextParser->handleLine(text, outputTypeForParser(d->nextParser, format));
|
||||||
switch (res.status) {
|
switch (res.status) {
|
||||||
case OutputLineParser::Status::Done:
|
case OutputLineParser::Status::Done:
|
||||||
|
d->nextParser->flush();
|
||||||
d->nextParser = nullptr;
|
d->nextParser = nullptr;
|
||||||
return res;
|
return res;
|
||||||
case OutputLineParser::Status::InProgress:
|
case OutputLineParser::Status::InProgress:
|
||||||
@@ -359,6 +360,7 @@ OutputLineParser::Result OutputFormatter::handleMessage(const QString &text, Out
|
|||||||
= parser->handleLine(text, outputTypeForParser(parser, format));
|
= parser->handleLine(text, outputTypeForParser(parser, format));
|
||||||
switch (res.status) {
|
switch (res.status) {
|
||||||
case OutputLineParser::Status::Done:
|
case OutputLineParser::Status::Done:
|
||||||
|
parser->flush();
|
||||||
involvedParsers << parser;
|
involvedParsers << parser;
|
||||||
return res;
|
return res;
|
||||||
case OutputLineParser::Status::InProgress:
|
case OutputLineParser::Status::InProgress:
|
||||||
|
@@ -51,8 +51,22 @@ public:
|
|||||||
if (!match.hasMatch())
|
if (!match.hasMatch())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
// Quick plausability test: If there's no slashes or dots, it's probably not a file.
|
||||||
|
const QString possibleFile = match.captured("file");
|
||||||
|
if (!possibleFile.contains('/') && !possibleFile.contains("'\\")
|
||||||
|
&& !possibleFile.contains('.')) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defer to the LdParser for some file types
|
||||||
|
if (possibleFile.endsWith(".o") || possibleFile.endsWith(".a")
|
||||||
|
|| possibleFile.endsWith("dll") || possibleFile.contains(".so")
|
||||||
|
|| possibleFile.endsWith("ld") || possibleFile.endsWith("ranlib")) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
Data data;
|
Data data;
|
||||||
data.rawFilePath = match.captured("file");
|
data.rawFilePath = possibleFile;
|
||||||
data.fileOffset = match.capturedStart("file");
|
data.fileOffset = match.capturedStart("file");
|
||||||
data.line = match.captured("line").toInt();
|
data.line = match.captured("line").toInt();
|
||||||
data.column = match.captured("column").toInt();
|
data.column = match.captured("column").toInt();
|
||||||
@@ -90,13 +104,13 @@ private:
|
|||||||
const QString typePrefix = "(?:fatal |#)";
|
const QString typePrefix = "(?:fatal |#)";
|
||||||
const QString fullTypeString
|
const QString fullTypeString
|
||||||
= QString::fromLatin1("(?<fullTypeString>%1?%2:?\\s)").arg(typePrefix, type);
|
= QString::fromLatin1("(?<fullTypeString>%1?%2:?\\s)").arg(typePrefix, type);
|
||||||
const QString lineAndOptionalColumn = "(?:(?<line>\\d+)(?::(?<column>\\d+))?)";
|
const QString optionalLineAndColumn = "(?:(?:(?<line>\\d+)(?::(?<column>\\d+))?):)?";
|
||||||
const QString binaryLocation = "\\(.*\\)"; // E.g. "(.text+0x40)"
|
const QString binaryLocation = "\\(.*\\)"; // E.g. "(.text+0x40)"
|
||||||
const QString fullLocation = QString::fromLatin1("%1(?:%2|%3)")
|
const QString fullLocation = QString::fromLatin1("%1(?:%2|%3)")
|
||||||
.arg(filePattern(), lineAndOptionalColumn, binaryLocation);
|
.arg(filePattern(), optionalLineAndColumn, binaryLocation);
|
||||||
const QString description = "(?<description>[^\\s].+)";
|
const QString description = "(?<description>[^\\s].+)";
|
||||||
|
|
||||||
return QString::fromLatin1("^%1:\\s+%2?%3$").arg(fullLocation, fullTypeString, description);
|
return QString::fromLatin1("^%1\\s+%2?%3$").arg(fullLocation, fullTypeString, description);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -105,18 +119,10 @@ GccParser::GccParser()
|
|||||||
{
|
{
|
||||||
setObjectName(QLatin1String("GCCParser"));
|
setObjectName(QLatin1String("GCCParser"));
|
||||||
|
|
||||||
m_regExpScope.setPattern(QLatin1Char('^') + filePattern()
|
|
||||||
+ "(?:(\\d+):)?(\\d+:)?\\s+((?:In .*(?:function|constructor) .*|At global scope|At top level):)$");
|
|
||||||
QTC_CHECK(m_regExpScope.isValid());
|
|
||||||
|
|
||||||
m_regExpIncluded.setPattern(QString::fromLatin1("\\bfrom\\s") + filePattern()
|
m_regExpIncluded.setPattern(QString::fromLatin1("\\bfrom\\s") + filePattern()
|
||||||
+ QLatin1String("(\\d+)(:\\d+)?[,:]?$"));
|
+ QLatin1String("(\\d+)(:\\d+)?[,:]?$"));
|
||||||
QTC_CHECK(m_regExpIncluded.isValid());
|
QTC_CHECK(m_regExpIncluded.isValid());
|
||||||
|
|
||||||
m_regExpInlined.setPattern(QString::fromLatin1("\\binlined from\\s.* at ")
|
|
||||||
+ filePattern() + "(\\d+)(:\\d+)?[,:]?$");
|
|
||||||
QTC_CHECK(m_regExpInlined.isValid());
|
|
||||||
|
|
||||||
m_regExpCc1plus.setPattern(QLatin1Char('^') + "cc1plus.*(error|warning): ((?:"
|
m_regExpCc1plus.setPattern(QLatin1Char('^') + "cc1plus.*(error|warning): ((?:"
|
||||||
+ filePattern() + " No such file or directory)?.*)");
|
+ filePattern() + " No such file or directory)?.*)");
|
||||||
QTC_CHECK(m_regExpCc1plus.isValid());
|
QTC_CHECK(m_regExpCc1plus.isValid());
|
||||||
@@ -177,8 +183,13 @@ OutputLineParser::Result GccParser::handleLine(const QString &line, OutputFormat
|
|||||||
const QString lne = rightTrimmed(line);
|
const QString lne = rightTrimmed(line);
|
||||||
|
|
||||||
// Blacklist some lines to not handle them:
|
// Blacklist some lines to not handle them:
|
||||||
if (lne.startsWith(QLatin1String("TeamBuilder ")) ||
|
if (lne.startsWith(QLatin1String("TeamBuilder "))
|
||||||
lne.startsWith(QLatin1String("distcc["))) {
|
|| lne.startsWith(QLatin1String("distcc["))
|
||||||
|
|| lne.contains("undefined reference")
|
||||||
|
|| lne.contains("undefined symbol")
|
||||||
|
|| lne.contains("duplicate symbol")
|
||||||
|
|| lne.contains("multiple definition")
|
||||||
|
|| lne.contains("ar: creating")) {
|
||||||
return Status::NotHandled;
|
return Status::NotHandled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,10 +216,6 @@ OutputLineParser::Result GccParser::handleLine(const QString &line, OutputFormat
|
|||||||
|
|
||||||
qCDebug(gccParserLog) << "checking regex" << m_regExpIncluded.pattern();
|
qCDebug(gccParserLog) << "checking regex" << m_regExpIncluded.pattern();
|
||||||
match = m_regExpIncluded.match(lne);
|
match = m_regExpIncluded.match(lne);
|
||||||
if (!match.hasMatch()) {
|
|
||||||
qCDebug(gccParserLog) << "checking regex" << m_regExpInlined.pattern();
|
|
||||||
match = m_regExpInlined.match(lne);
|
|
||||||
}
|
|
||||||
if (match.hasMatch()) {
|
if (match.hasMatch()) {
|
||||||
const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured("file")));
|
const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured("file")));
|
||||||
const int lineNo = match.captured(2).toInt();
|
const int lineNo = match.captured(2).toInt();
|
||||||
@@ -229,7 +236,6 @@ OutputLineParser::Result GccParser::handleLine(const QString &line, OutputFormat
|
|||||||
if (!filePath.isEmpty())
|
if (!filePath.isEmpty())
|
||||||
addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, -1, match, 3);
|
addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, -1, match, 3);
|
||||||
gccCreateOrAmendTask(type, match.captured(2), lne, false, filePath, -1, 0, linkSpecs);
|
gccCreateOrAmendTask(type, match.captured(2), lne, false, filePath, -1, 0, linkSpecs);
|
||||||
flush();
|
|
||||||
return {Status::Done, linkSpecs};
|
return {Status::Done, linkSpecs};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,20 +249,6 @@ OutputLineParser::Result GccParser::handleLine(const QString &line, OutputFormat
|
|||||||
return {Status::InProgress, linkSpecs};
|
return {Status::InProgress, linkSpecs};
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(gccParserLog) << "checking regex" << m_regExpScope.pattern();
|
|
||||||
match = m_regExpScope.match(lne);
|
|
||||||
if (match.hasMatch()) {
|
|
||||||
const int lineno = match.captured(2).toInt();
|
|
||||||
const int column = match.captured(3).toInt();
|
|
||||||
const QString description = match.captured(4);
|
|
||||||
const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured("file")));
|
|
||||||
LinkSpecs linkSpecs;
|
|
||||||
addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineno, match, "file");
|
|
||||||
gccCreateOrAmendTask(
|
|
||||||
Task::Unknown, description, lne, false, filePath, lineno, column, linkSpecs);
|
|
||||||
return {Status::InProgress, linkSpecs};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((lne.startsWith(' ') && !currentTask().isNull()) || isContinuation(lne)) {
|
if ((lne.startsWith(' ') && !currentTask().isNull()) || isContinuation(lne)) {
|
||||||
gccCreateOrAmendTask(Task::Unknown, lne, lne, true);
|
gccCreateOrAmendTask(Task::Unknown, lne, lne, true);
|
||||||
return Status::InProgress;
|
return Status::InProgress;
|
||||||
@@ -439,8 +431,7 @@ void ProjectExplorerTest::testGccOutputParsers_data()
|
|||||||
FilePath::fromUserInput("C:\\temp\\test\\untitled8/main.cpp"),
|
FilePath::fromUserInput("C:\\temp\\test\\untitled8/main.cpp"),
|
||||||
8, 0,
|
8, 0,
|
||||||
formatRanges)
|
formatRanges)
|
||||||
<< CompileTask(Task::Error,
|
<< CompileTask(Task::Error, "collect2: ld returned 1 exit status"))
|
||||||
"collect2: ld returned 1 exit status"))
|
|
||||||
<< QString();
|
<< QString();
|
||||||
|
|
||||||
formatRanges.clear();
|
formatRanges.clear();
|
||||||
@@ -465,8 +456,7 @@ void ProjectExplorerTest::testGccOutputParsers_data()
|
|||||||
FilePath::fromUserInput("C:\\temp\\test\\untitled8/main.cpp"),
|
FilePath::fromUserInput("C:\\temp\\test\\untitled8/main.cpp"),
|
||||||
-1, 0,
|
-1, 0,
|
||||||
formatRanges)
|
formatRanges)
|
||||||
<< CompileTask(Task::Error,
|
<< CompileTask(Task::Error, "collect2: ld returned 1 exit status"))
|
||||||
"collect2: ld returned 1 exit status"))
|
|
||||||
<< QString();
|
<< QString();
|
||||||
|
|
||||||
QTest::newRow("linker: dll format not recognized")
|
QTest::newRow("linker: dll format not recognized")
|
||||||
@@ -989,7 +979,7 @@ void ProjectExplorerTest::testGccOutputParsers_data()
|
|||||||
<< formatRange(31, 28)
|
<< formatRange(31, 28)
|
||||||
<< formatRange(59, 23, "olpfile:///home/user/test/foo.cpp::2::-1")
|
<< formatRange(59, 23, "olpfile:///home/user/test/foo.cpp::2::-1")
|
||||||
<< formatRange(82, 34))
|
<< formatRange(82, 34))
|
||||||
<< CompileTask(Task::Unknown,
|
<< CompileTask(Task::Error,
|
||||||
"first defined here",
|
"first defined here",
|
||||||
FilePath::fromUserInput("/home/user/test/bar.cpp"),
|
FilePath::fromUserInput("/home/user/test/bar.cpp"),
|
||||||
4)
|
4)
|
||||||
@@ -1007,7 +997,7 @@ void ProjectExplorerTest::testGccOutputParsers_data()
|
|||||||
<< CompileTask(Task::Error,
|
<< CompileTask(Task::Error,
|
||||||
"multiple definition of `foo'",
|
"multiple definition of `foo'",
|
||||||
FilePath::fromUserInput("foo.o"), -1)
|
FilePath::fromUserInput("foo.o"), -1)
|
||||||
<< CompileTask(Task::Unknown,
|
<< CompileTask(Task::Error,
|
||||||
"first defined here",
|
"first defined here",
|
||||||
FilePath::fromUserInput("bar.o"), -1)
|
FilePath::fromUserInput("bar.o"), -1)
|
||||||
<< CompileTask(Task::Error,
|
<< CompileTask(Task::Error,
|
||||||
@@ -1465,6 +1455,37 @@ void ProjectExplorerTest::testGccOutputParsers_data()
|
|||||||
<< Tasks{CompileTask(Task::Error, "blubb", "/home/tim/path/to/sources/and/more.h",
|
<< Tasks{CompileTask(Task::Error, "blubb", "/home/tim/path/to/sources/and/more.h",
|
||||||
15, 22)}
|
15, 22)}
|
||||||
<< QString();
|
<< QString();
|
||||||
|
|
||||||
|
QTest::newRow("no line number")
|
||||||
|
<< QString::fromUtf8("In file included from /data/dev/creator/src/libs/utils/aspects.cpp:12:\n"
|
||||||
|
"/data/dev/creator/src/libs/utils/layoutbuilder.h: In instantiation of ‘Layouting::BuilderItem<X, XInterface>::I::I(const Inner&) [with Inner = Utils::BaseAspect; X = Layouting::Row; XInterface = Layouting::LayoutInterface]’:\n"
|
||||||
|
"/data/dev/creator/src/libs/utils/aspects.cpp:3454:13: required from here\n"
|
||||||
|
"/data/dev/creator/src/libs/utils/layoutbuilder.h:79:51: error: use of deleted function ‘Utils::BaseAspect::BaseAspect(const Utils::BaseAspect&)’\n"
|
||||||
|
" 79 | apply = [p](XInterface *x) { doit_nest(x, p); };\n"
|
||||||
|
" | ~~~~~~~~^~~~~")
|
||||||
|
<< OutputParserTester::STDERR
|
||||||
|
<< QString() << QString()
|
||||||
|
<< (Tasks{compileTask(
|
||||||
|
Task::Error,
|
||||||
|
"use of deleted function ‘Utils::BaseAspect::BaseAspect(const Utils::BaseAspect&)’\n"
|
||||||
|
"In file included from /data/dev/creator/src/libs/utils/aspects.cpp:12:\n"
|
||||||
|
"/data/dev/creator/src/libs/utils/layoutbuilder.h: In instantiation of ‘Layouting::BuilderItem<X, XInterface>::I::I(const Inner&) [with Inner = Utils::BaseAspect; X = Layouting::Row; XInterface = Layouting::LayoutInterface]’:\n"
|
||||||
|
"/data/dev/creator/src/libs/utils/aspects.cpp:3454:13: required from here\n"
|
||||||
|
"/data/dev/creator/src/libs/utils/layoutbuilder.h:79:51: error: use of deleted function ‘Utils::BaseAspect::BaseAspect(const Utils::BaseAspect&)’\n"
|
||||||
|
" 79 | apply = [p](XInterface *x) { doit_nest(x, p); };\n"
|
||||||
|
" | ~~~~~~~~^~~~~",
|
||||||
|
FilePath::fromUserInput("/data/dev/creator/src/libs/utils/aspects.cpp"), 3454, 13,
|
||||||
|
QVector<QTextLayout::FormatRange>{
|
||||||
|
formatRange(82, 22),
|
||||||
|
formatRange(104, 44, "olpfile:///data/dev/creator/src/libs/utils/aspects.cpp::12::-1"),
|
||||||
|
formatRange(148, 5),
|
||||||
|
formatRange(153, 48, "olpfile:///data/dev/creator/src/libs/utils/layoutbuilder.h::0::-1"),
|
||||||
|
formatRange(201, 177),
|
||||||
|
formatRange(378, 44, "olpfile:///data/dev/creator/src/libs/utils/aspects.cpp::3454::-1"),
|
||||||
|
formatRange(422, 31),
|
||||||
|
formatRange(453, 48, "olpfile:///data/dev/creator/src/libs/utils/layoutbuilder.h::79::-1"),
|
||||||
|
formatRange(501, 228)})})
|
||||||
|
<< QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectExplorerTest::testGccOutputParsers()
|
void ProjectExplorerTest::testGccOutputParsers()
|
||||||
|
@@ -38,9 +38,7 @@ private:
|
|||||||
|
|
||||||
bool isContinuation(const QString &newLine) const override;
|
bool isContinuation(const QString &newLine) const override;
|
||||||
|
|
||||||
QRegularExpression m_regExpScope;
|
|
||||||
QRegularExpression m_regExpIncluded;
|
QRegularExpression m_regExpIncluded;
|
||||||
QRegularExpression m_regExpInlined;
|
|
||||||
QRegularExpression m_regExpGccNames;
|
QRegularExpression m_regExpGccNames;
|
||||||
QRegularExpression m_regExpCc1plus;
|
QRegularExpression m_regExpCc1plus;
|
||||||
};
|
};
|
||||||
|
@@ -39,46 +39,49 @@ Utils::OutputLineParser::Result LdParser::handleLine(const QString &line, Utils:
|
|||||||
return Status::NotHandled;
|
return Status::NotHandled;
|
||||||
|
|
||||||
QString lne = rightTrimmed(line);
|
QString lne = rightTrimmed(line);
|
||||||
if (!lne.isEmpty() && !lne.at(0).isSpace() && !currentTask().isNull()) {
|
|
||||||
flush();
|
|
||||||
return Status::NotHandled;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lne.startsWith(QLatin1String("TeamBuilder "))
|
if (lne.startsWith(QLatin1String("TeamBuilder "))
|
||||||
|| lne.startsWith(QLatin1String("distcc["))
|
|| lne.startsWith(QLatin1String("distcc["))
|
||||||
|| lne.contains(QLatin1String("ar: creating "))) {
|
|| lne.contains(QLatin1String("ar: creating "))) {
|
||||||
return Status::NotHandled;
|
return Status::NotHandled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto getStatus = [&lne] { return lne.endsWith(':') ? Status::InProgress : Status::Done; };
|
||||||
|
|
||||||
// ld on macOS
|
// ld on macOS
|
||||||
if (lne.startsWith("Undefined symbols for architecture") && lne.endsWith(":")) {
|
if (lne.startsWith("Undefined symbols for architecture") && getStatus() == Status::InProgress) {
|
||||||
createOrAmendTask(Task::Error, lne, line);
|
createOrAmendTask(Task::Error, lne, line);
|
||||||
return Status::InProgress;
|
return Status::InProgress;
|
||||||
}
|
}
|
||||||
if (!currentTask().isNull() && lne.startsWith(" ")) {
|
|
||||||
|
if (!currentTask().isNull() && isContinuation(line)) {
|
||||||
static const QRegularExpression locRegExp(" (?<symbol>\\S+) in (?<file>\\S+)");
|
static const QRegularExpression locRegExp(" (?<symbol>\\S+) in (?<file>\\S+)");
|
||||||
const QRegularExpressionMatch match = locRegExp.match(lne);
|
const QRegularExpressionMatch match = locRegExp.match(lne);
|
||||||
LinkSpecs linkSpecs;
|
LinkSpecs linkSpecs;
|
||||||
Utils::FilePath filePath;
|
Utils::FilePath filePath;
|
||||||
|
bool handle = false;
|
||||||
if (match.hasMatch()) {
|
if (match.hasMatch()) {
|
||||||
|
handle = true;
|
||||||
filePath = absoluteFilePath(Utils::FilePath::fromString(match.captured("file")));
|
filePath = absoluteFilePath(Utils::FilePath::fromString(match.captured("file")));
|
||||||
addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, 0, match, "file");
|
addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, 0, match, "file");
|
||||||
currentTask().setFile(filePath);
|
currentTask().setFile(filePath);
|
||||||
|
} else {
|
||||||
|
handle = !lne.isEmpty() && lne.at(0).isSpace();
|
||||||
}
|
}
|
||||||
|
if (handle) {
|
||||||
createOrAmendTask(Task::Unknown, {}, line, true, filePath);
|
createOrAmendTask(Task::Unknown, {}, line, true, filePath);
|
||||||
return {Status::InProgress, linkSpecs};
|
return {Status::InProgress, linkSpecs};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (lne.startsWith("collect2:") || lne.startsWith("collect2.exe:")) {
|
if (lne.startsWith("collect2:") || lne.startsWith("collect2.exe:")) {
|
||||||
scheduleTask(CompileTask(Task::Error, lne /* description */), 1);
|
createOrAmendTask(Task::Error, lne, line);
|
||||||
return Status::Done;
|
return getStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
QRegularExpressionMatch match = m_ranlib.match(lne);
|
QRegularExpressionMatch match = m_ranlib.match(lne);
|
||||||
if (match.hasMatch()) {
|
if (match.hasMatch()) {
|
||||||
QString description = match.captured(2);
|
createOrAmendTask(Task::Warning, match.captured(2), line);
|
||||||
scheduleTask(CompileTask(Task::Warning, description), 1);
|
return getStatus();
|
||||||
return Status::Done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match = m_regExpGccNames.match(lne);
|
match = m_regExpGccNames.match(lne);
|
||||||
@@ -91,8 +94,8 @@ Utils::OutputLineParser::Result LdParser::handleLine(const QString &line, Utils:
|
|||||||
} else if (description.startsWith(QLatin1String("fatal: "))) {
|
} else if (description.startsWith(QLatin1String("fatal: "))) {
|
||||||
description = description.mid(7);
|
description = description.mid(7);
|
||||||
}
|
}
|
||||||
scheduleTask(CompileTask(type, description), 1);
|
createOrAmendTask(type, description, line);
|
||||||
return Status::Done;
|
return getStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
match = m_regExpLinker.match(lne);
|
match = m_regExpLinker.match(lne);
|
||||||
@@ -101,41 +104,47 @@ Utils::OutputLineParser::Result LdParser::handleLine(const QString &line, Utils:
|
|||||||
int lineno = match.captured(7).toInt(&ok);
|
int lineno = match.captured(7).toInt(&ok);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
lineno = -1;
|
lineno = -1;
|
||||||
Utils::FilePath filename
|
Utils::FilePath filePath
|
||||||
= absoluteFilePath(Utils::FilePath::fromUserInput(match.captured(1)));
|
= absoluteFilePath(Utils::FilePath::fromUserInput(match.captured(1)));
|
||||||
int capIndex = 1;
|
int capIndex = 1;
|
||||||
const QString sourceFileName = match.captured(4);
|
const QString sourceFileName = match.captured(4);
|
||||||
if (!sourceFileName.isEmpty()
|
if (!sourceFileName.isEmpty()
|
||||||
&& !sourceFileName.startsWith(QLatin1String("(.text"))
|
&& !sourceFileName.startsWith(QLatin1String("(.text"))
|
||||||
&& !sourceFileName.startsWith(QLatin1String("(.data"))) {
|
&& !sourceFileName.startsWith(QLatin1String("(.data"))) {
|
||||||
filename = absoluteFilePath(Utils::FilePath::fromUserInput(sourceFileName));
|
filePath = absoluteFilePath(Utils::FilePath::fromUserInput(sourceFileName));
|
||||||
capIndex = 4;
|
capIndex = 4;
|
||||||
}
|
}
|
||||||
QString description = match.captured(8).trimmed();
|
QString description = match.captured(8).trimmed();
|
||||||
Task::TaskType type = Task::Error;
|
|
||||||
if (description.startsWith(QLatin1String("first defined here")) ||
|
|
||||||
description.startsWith(QLatin1String("note:"), Qt::CaseInsensitive)) {
|
|
||||||
type = Task::Unknown;
|
|
||||||
} else if (description.startsWith(QLatin1String("warning: "), Qt::CaseInsensitive)) {
|
|
||||||
type = Task::Warning;
|
|
||||||
description = description.mid(9);
|
|
||||||
}
|
|
||||||
static const QStringList keywords{
|
static const QStringList keywords{
|
||||||
"File format not recognized",
|
"File format not recognized",
|
||||||
"undefined reference",
|
"undefined reference",
|
||||||
|
"multiple definition",
|
||||||
"first defined here",
|
"first defined here",
|
||||||
"feupdateenv is not implemented and will always fail", // yes, this is quite special ...
|
"feupdateenv is not implemented and will always fail", // yes, this is quite special ...
|
||||||
};
|
};
|
||||||
const auto descriptionContainsKeyword = [&description](const QString &keyword) {
|
const auto descriptionContainsKeyword = [&description](const QString &keyword) {
|
||||||
return description.contains(keyword);
|
return description.contains(keyword);
|
||||||
};
|
};
|
||||||
if (Utils::anyOf(keywords, descriptionContainsKeyword)) {
|
Task::TaskType type = Task::Unknown;
|
||||||
|
const bool hasKeyword = Utils::anyOf(keywords, descriptionContainsKeyword);
|
||||||
|
if (description.startsWith(QLatin1String("warning: "), Qt::CaseInsensitive)) {
|
||||||
|
type = Task::Warning;
|
||||||
|
description = description.mid(9);
|
||||||
|
} else if (hasKeyword) {
|
||||||
|
type = Task::Error;
|
||||||
|
}
|
||||||
|
if (hasKeyword || filePath.fileName().endsWith(".o")) {
|
||||||
LinkSpecs linkSpecs;
|
LinkSpecs linkSpecs;
|
||||||
addLinkSpecForAbsoluteFilePath(linkSpecs, filename, lineno, match, capIndex);
|
addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineno, match, capIndex);
|
||||||
scheduleTask(CompileTask(type, description, filename, lineno), 1);
|
createOrAmendTask(type, description, line, false, filePath, lineno, 0, linkSpecs);
|
||||||
return {Status::Done, linkSpecs};
|
return {getStatus(), linkSpecs};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Status::NotHandled;
|
return Status::NotHandled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LdParser::isContinuation(const QString &line) const
|
||||||
|
{
|
||||||
|
return currentTask().details.last().endsWith(':') || (!line.isEmpty() && line.at(0).isSpace());
|
||||||
|
}
|
||||||
|
@@ -17,6 +17,7 @@ public:
|
|||||||
LdParser();
|
LdParser();
|
||||||
private:
|
private:
|
||||||
Result handleLine(const QString &line, Utils::OutputFormat type) override;
|
Result handleLine(const QString &line, Utils::OutputFormat type) override;
|
||||||
|
bool isContinuation(const QString &line) const override;
|
||||||
|
|
||||||
QRegularExpression m_ranlib;
|
QRegularExpression m_ranlib;
|
||||||
QRegularExpression m_regExpLinker;
|
QRegularExpression m_regExpLinker;
|
||||||
|
Reference in New Issue
Block a user