From b76590181a7990255462daee460f49e477ff4114 Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Tue, 14 Jan 2025 23:54:55 +0100 Subject: [PATCH] Improve msvc output parser --- src/plugins/projectexplorer/ioutputparser.cpp | 11 -- src/plugins/projectexplorer/ioutputparser.h | 3 - src/plugins/projectexplorer/msvcparser.cpp | 105 +++++++++++------- 3 files changed, 67 insertions(+), 52 deletions(-) diff --git a/src/plugins/projectexplorer/ioutputparser.cpp b/src/plugins/projectexplorer/ioutputparser.cpp index 76f217854cb..ad420d15047 100644 --- a/src/plugins/projectexplorer/ioutputparser.cpp +++ b/src/plugins/projectexplorer/ioutputparser.cpp @@ -73,17 +73,6 @@ const QList OutputTaskParser::taskInfo() const return d->scheduledTasks; } -bool OutputTaskParser::hasCurrentTask() const -{ - return !d->currentTask.isNull(); -} - -void OutputTaskParser::amendTaskDetails(const QString &originalLine) -{ - d->currentTask.details.append(originalLine); - ++d->lineCount; -} - void OutputTaskParser::scheduleTask(const Task &task, int outputLines, int skippedLines) { TaskInfo ts(task, outputLines, skippedLines); diff --git a/src/plugins/projectexplorer/ioutputparser.h b/src/plugins/projectexplorer/ioutputparser.h index 503c0f70955..de2ee9ebfca 100644 --- a/src/plugins/projectexplorer/ioutputparser.h +++ b/src/plugins/projectexplorer/ioutputparser.h @@ -29,9 +29,6 @@ class PROJECTEXPLORER_EXPORT OutputTaskParser : public Utils::OutputLineParser const QList taskInfo() const; protected: - bool hasCurrentTask() const; - void amendTaskDetails(const QString &originalLine); - void flush() override; void scheduleTask(const Task &task, int outputLines, int skippedLines = 0); diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp index d644ab8474a..27790089959 100644 --- a/src/plugins/projectexplorer/msvcparser.cpp +++ b/src/plugins/projectexplorer/msvcparser.cpp @@ -12,34 +12,62 @@ using namespace Utils; -// As of MSVC 2015: "foo.cpp(42) :" -> "foo.cpp(42):" -static const char FILE_POS_PATTERN[] = "^(?:\\d+>)?(cl|LINK|.+?[^ ]) ?: "; +namespace { -static QPair parseFileName(const QString &input) +auto constexpr filePosRegexString() -> std::string_view { + // As of MSVC 2015: "foo.cpp(42) :" -> "foo.cpp(42):" + return R"(^(?:\d+>)?(cl|LINK|.+?[^ ]) ?: )"; +} + +struct FileData { + FilePath fileName{}; + int lineNo{-1}; + int columnNo{-1}; +}; + +auto parseFileName(QStringView input) -> FileData { - QString fileName = input; - if (fileName.startsWith("LINK") || fileName.startsWith("cl")) - return {{}, -1}; + auto result = FileData{}; + + if (input.startsWith(QStringView{u"LINK "}) || input.startsWith(QStringView{u"cl "})){ + return result; + } + auto& [fileName, lineNo, columnNo] = result; // Extract linenumber (if it is there): - int linenumber = -1; - if (fileName.endsWith(')')) { - int pos = fileName.lastIndexOf('('); - if (pos >= 0) { - // clang-cl gives column, too: "foo.cpp(34,1)" as opposed to MSVC "foo.cpp(34)". - int endPos = fileName.indexOf(',', pos + 1); - if (endPos < 0) - endPos = fileName.size() - 1; - bool ok = false; - const int n = fileName.mid(pos + 1, endPos - pos - 1).toInt(&ok); - if (ok) { - fileName = fileName.left(pos); - linenumber = n; + if (input.size() > 2 && input.endsWith(')')) { + auto rit = input.rbegin() + 1; + auto rend = input.rend(); + auto f = 0; + auto n = -1; + while (rit != rend) { + auto ch = *rit++; + if (ch.isDigit()) { + if (n < 0) { + n = ch.digitValue(); + f = 10; + } + else { + n += ch.digitValue() * f; + f *= 10; + } + continue; } + if (ch == u',') { + if (n >= 0) columnNo = n; + n = -1; + continue; + } + if (ch == u'(') { + if (n >= 0) lineNo = n; + input = input.sliced(0, rend - rit); + break; + } + break; } } - const QString normalized = FileUtils::normalizedPathName(fileName); - return {FilePath::fromUserInput(normalized), linenumber}; + fileName = FilePath::fromUserInput(FileUtils::normalizedPathName(input.toString())); + return result; } using namespace ProjectExplorer; @@ -74,13 +102,15 @@ static Task::TaskType taskType(const QString &category) return type; } +} // namespace + MsvcParser::MsvcParser() { setObjectName("MsvcParser"); - m_compileRegExp.setPattern(QString(FILE_POS_PATTERN) - + ".*(?:(warning|error) ([A-Z]+\\d{4} ?: )|note: )(.*)$"); + m_compileRegExp.setPattern(QLatin1String(filePosRegexString()) + + R"(.*(?:(warning|error) ([A-Z]+\d{4} ?: )|note: )(.*)$)"); QTC_CHECK(m_compileRegExp.isValid()); - m_additionalInfoRegExp.setPattern("^ (?:(could be |or )\\s*')?(.*)\\((\\d+)\\) : (.*)$"); + m_additionalInfoRegExp.setPattern(R"(^ (?:(could be |or )\s*')?(.*)\((\d+)\) : (.*)$)"); QTC_CHECK(m_additionalInfoRegExp.isValid()); } @@ -115,19 +145,19 @@ MsvcParser::Result MsvcParser::processCompileLine(const QString &line) m_isCaretDiagnostics = line.contains("/diagnostics:caret"); } if (QRegularExpressionMatch match = m_compileRegExp.match(line); match.hasMatch()) { - QPair position = parseFileName(match.captured(1)); - const FilePath filePath = absoluteFilePath(position.first); + auto [rawFileName, lineNo, columnNo] = parseFileName(match.captured(1)); + const FilePath filePath = absoluteFilePath(rawFileName); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, position.second, -1, match, 1); - const QString &description = match.captured(3) + match.captured(4).trimmed(); + addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, columnNo, match, 1); + const auto description = match.captured(3) + match.captured(4).trimmed(); createOrAmendTask( taskType(match.captured(2)), description, line, false, filePath, - position.second, - 0, + lineNo, + columnNo > 0 ? columnNo : 0, linkSpecs); m_expectCode = m_isCaretDiagnostics; return {Status::InProgress, linkSpecs}; @@ -144,7 +174,7 @@ MsvcParser::Result MsvcParser::processCompileLine(const QString &line) m_expectCode = m_isCaretDiagnostics; return {Status::InProgress, linkSpecs}; } - if (hasCurrentTask()) { + if (!currentTask().isNull()) { bool amend = false; if (line.endsWith("^")) { m_expectCode = false; // code was before @@ -158,7 +188,7 @@ MsvcParser::Result MsvcParser::processCompileLine(const QString &line) amend = true; } if (amend) { - amendTaskDetails(line); + createOrAmendTask(Task::Unknown, {}, line, true); return Status::InProgress; } } @@ -176,7 +206,7 @@ MsvcParser::Result MsvcParser::processCompileLine(const QString &line) // ".\qwindowsgdinativeinterface.cpp(48,3) : error: unknown type name 'errr'" static inline QString clangClCompilePattern() { - return QLatin1String(FILE_POS_PATTERN) + " ?(warning|error): (.*)$"; + return QLatin1String(filePosRegexString()) + " ?(warning|error): (.*)$"; } ClangClParser::ClangClParser() @@ -227,13 +257,12 @@ OutputLineParser::Result ClangClParser::handleLine(const QString &line, OutputFo QRegularExpressionMatch match = m_compileRegExp.match(lne); if (match.hasMatch()) { flush(); - const QPair position = parseFileName(match.captured(1)); - const FilePath file = absoluteFilePath(position.first); - const int lineNo = position.second; + const auto [rawFileName, lineNo, columnNo] = parseFileName(match.captured(1)); + const FilePath file = absoluteFilePath(rawFileName); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineNo, -1, match, 1); + addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineNo, columnNo, match, 1); createOrAmendTask( - taskType(match.captured(2)), match.captured(3).trimmed(), line, false, file, lineNo); + taskType(match.captured(2)), match.captured(3).trimmed(), line, false, file, lineNo, columnNo, linkSpecs); return {Status::InProgress, linkSpecs}; }